[net.lang.c] Dead functions and /*NOTREACHED*/

jbuck@epimass.UUCP (Joe Buck) (08/21/86)

In article <86900019@haddock> karl@haddock (The Walking Lint) writes:
>[discussion of some problems with adding "dead functions" to C]
>But I really hate having to write /*NOTREACHED*/ to keep lint happy!

There's a fix for this that doesn't do violence to the language.
There should be another "special comment" lint recognizes that's
present in the lint library (/*DEADEND*/ or something).  Then
functions like "exit" are marked once in the lint library, and
user-written functions that always call exit would also be understood
to be "dead".  Voila! lint now understands about exit, and is able
to find unreachable code that it currently may miss.

While I'm at it, a similar comment could be added to tell lint that
a function like malloc or calloc always returns an aligned pointer.
I understand that ANSI C has a different solution for this, but
every (void *) pointer isn't guaranteed to be aligned, so I suspect
that the ANSI solution will cause problems elsewhere.

-- 
- Joe Buck 	{ihnp4!pesnta,oliveb,nsc!csi}!epimass!jbuck
  Entropic Processing, Inc., Cupertino, California

karl@haddock (09/03/86)

epimass!jbuck (Joe Buck) writes:
>In article <86900019@haddock> karl@haddock (The Walking Lint) writes:
>>[discussion of some problems with adding "dead functions" to C]
>>But I really hate having to write /*NOTREACHED*/ to keep lint happy!
>
>There's a fix for this that doesn't do violence to the language.
>There should be another "special comment" lint recognizes that's
>present in the lint library (/*DEADEND*/ or something).  Then
>functions like "exit" are marked once in the lint library, and
>user-written functions that always call exit would also be understood
>to be "dead".  Voila! lint now understands about exit, and is able
>to find unreachable code that it currently may miss.

(I don't think adding a new type is "violence to the language", but...)
Not bad; it doesn't help with the compiler's optimization, but it would take
care of the /*NOTREACHED*/ problem.  And the user can use /*DEADEND*/ on his
own functions even if lint isn't smart enough to propagate dead-knowledge.
(If it is, then the magic comment may not even be necessary; the line
	void    exit(int) { for (;;); }
int the lint library should suffice.)

>While I'm at it, a similar comment could be added to tell lint that
>a function like malloc or calloc always returns an aligned pointer.

Perhaps.

>I understand that ANSI C has a different solution for this,

No.  "void *" has nothing to do with guaranteed alignment, it just means
"pointer to unknown".

Karl W. Z. Heuer (ima!haddock!karl; karl@haddock.isc.com), The Walking Lint

guy@sun.uucp (Guy Harris) (09/04/86)

> >While I'm at it, a similar comment could be added to tell lint that
> >a function like malloc or calloc always returns an aligned pointer.
> 
> Perhaps.

*Some* way to tell lint to shut the @#!!%%#@ up about pointer alignment
problems, even if the most stringent checking is enabled, is required;
complaints about "possible pointer alignment problems" when "malloc" is used
are pure noise.

> >I understand that ANSI C has a different solution for this,
> 
> No.  "void *" has nothing to do with guaranteed alignment, it just means
> "pointer to unknown".

ANSI C doesn't seem to have much to say about pointer alignment in general -
at least I couldn't find anything about it in the obvious places suggested
by the index (this may be a bug in the index).  However, nothing prevents a
compiler or "lint" from treating *all* "void *" pointers as always being
properly aligned; the most common uses of "void *" are 1) as the result of a
storage-allocation function - in this case, it can be assumed that the
function is returning something properly aligned, and 2) as an "opaque
pointer", used when a data structure is used to refer to objects of several
different types (and the set of object types cannot be determined when the
code is written, so a union can't be used) - in this case, the compiler
can't do the checking properly anyway, so warnings are largely useless.
-- 
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com (or guy@sun.arpa)

karl@haddock (09/08/86)

sun!guy (Guy Harris) writes:
>complaints about "possible pointer alignment problems" when "malloc" is used
>are pure noise.

Certainly.  I guess the addition of a lint comment (on the *declaration* of
malloc, not its use, of course) is a pretty clean way to handle it.  A
pointer type that (unlike "void *") is guaranteed to be fully aligned would
solve it too (and be more efficient on word-addressible machines), but since
only malloc et al would use it, it's not worth a language change.

>Nothing prevents a compiler or "lint" from treating *all* "void *" pointers
>as always being properly aligned;

If you mean a compiler can generate code assuming "void *" is always aligned,
you're wrong -- the user can legally stuff a "char *" value into a "void *"
object.  I assume you mean the compiler/lint can be silent about uncasted
assignments like "intp = voidp".

>the most common uses of "void *" are [malloc and] when a data structure is
>used [as a pseudo-union of pointers] - in this case, the compiler can't do
>the checking properly anyway, so warnings are largely useless.

The former is actually a special case of the latter, the only difference
being that the result is known to be maximally aligned.  I think the only
other functions that return "void *" (in X3J11 01-May-1986) are those like
bsearch() and memcpy(), which expect arguments of arbitrary pointer type
cast into "void *", and return the same.  The problem is that the compiler
isn't smart enough to know that "(int *)memcpy((void *)intp, (void *)intp);"
is correct whereas "voidp = (void *)charp; intp = (int *)voidp;" is likely
to cause trouble.  In my opinion, the best solution is to assume that the
user knows what he's doing if an explicit cast is present, and otherwise
give a warning message.  (Likewise for using an int in a float context.)

Btw, I sometimes handle the malloc problem with the (ANSIfied) code below,
which can easily be modified for other functions like memcpy().

#ifdef lint
extern int    *imalloc(unsigned int);
extern double *dmalloc(unsigned int);
#else
extern void   *malloc(unsigned int);
#define imalloc(n) ((int    *)malloc((n)*sizeof(int)))
#define dmalloc(n) ((double *)malloc((n)*sizeof(double)))
#endif

Karl W. Z. Heuer (ima!haddock!karl; karl@haddock.isc.com), The Walking Lint