[net.lang.c] New LINT gag wanted

ok@edai.UUCP (Richard O'Keefe) (03/06/84)

    The general problem with Lint is that the programs it is most needed
for are the ones it is least usable on.  I've been trying to clean up  a
moderately  large  (7500-line)  C  program  recently,  and the following
things have proven particularly annoying.

1.  I am worried about portability of the  program  to  32-bit  machines
    whose  C  compiler  defines  int=short.   I  am told that the ONYX C
    compiler for the Z8000 does this.  I have carefully gone through the
    program writing "long" everywhere  it  matters,  and  putting  "int"
    where  it doesn't. But I didn't write the program.  So I wanted Lint
    to find the places I'd missed.  And you'd think  that  the  -a  flag
    would  be  exactly  what  you  want.   Indeed,  the -a flag DID find
    **one**  place  I'd  missed,  which  could   have   had   disastrous
    consequences.  BUT it also found over 50 other places, mostly of the
    form
		L =<< k;

    where L had been declared long.  (There were other things  with  the
    same symptom but different etiologies.)

	WANTED: an option which reports on "int" := "long" and NOTHING ELSE.

    When I want to know about L =<< k, and I'm not silly enough to think
    that I shouldn't check these, I would rather have another option for
    that specific problem.

2.  The program contains the following:

	#include <stdio.h>		/* defines NULL */
	typedef long **ptr;
	ptr foo;
	baz(x)
	    ptr x;
	    {...}
	... baz(NULL); ... foo = NULL; ... baz(foo); ...

    Lint is perfectly happy with foo = NULL;  but  complains  about  the
    "inconsistent  usage"  of  baz's first argument.  Given that K&R say
    that 0 is an acceptable pointer of any type, I don't  find  this  at
    all  helpful.   This happens a lot in this particular program.  What
    I'm worried about is functions with an "int" argument  being  passed
    "long"  values,  having  to wade through some 34 bogus complaints of
    this nature really doesn't help.

3.  The program has been ported from a VAX to a PERQ running ICL's PaNiX
    version of UNIX.  PERQ pointers are normally to multiples of 16 bits,
    so char* and short* have a different representation.   It's also been
    ported a machine whose normal addresses are long*.  It *seems* to run
    on these machines, but as development takes place on the VAX it would
    be nice to check that future versions will port as well.   So pointer
    alignment problems are very interesting.   The trouble is that I know
    in advance that certain combinations will NOT cause problems on these
    machines.

	WANTED: a Lint declaration like /*ALIGNOK type1 type2*/

    This declaration would mean that it is up to me to ensure that type1*
    can safely be converted to type2*.  An instance of what I mean is

	typedef struct ugh
	    {
		long a;
		struct ugh *b;
	    } ugh, *ughp;

	/*ALIGNOK long ugh*/

    The idea is that you would start out with none of these declarations,
    and Lint would find all the alignment problems it now reports.  You'd
    check through them, and you'd find some that were ok, so you'd add an
    ALIGNOK declaration, and re-run Lint.  You'd finally end up with just
    the set of alignment assumptions you needed, and if you wanted to try
    another machine, these declarations would tell you precisely which of
    the many possible combinations your program relied on.

I have no access to the source of Lint. (We're running 4.1bsd.)  Based on
what I know about compiling in general, it doesn't seem all that tough to
make these changes.  Does anyone in netland know why it would be either
impossible or undesirable to do so?  Better still, has someone got a Lint
we can copy that already has these or similar changes?

gwyn@brl-vgr.ARPA (Doug Gwyn ) (03/07/84)

When "lint" says that ptr = 0; is okay but func( 0 ) isn't where func()
expects a pointer argument, you should believe it.

johanw@ttds.UUCP (Johan Wide'n) (03/08/84)

Another feature that would be nice to have in connection with
braindamaged compilers with sizeof(int) != sizeof(char *) :
	Lint should tell you when the difference of two pointers
is taken. (The result is an int.)

To ensure portability we have been forced to hide the diff of pointers in
a macro. For a 32-bit pointer, 16-bit int machine this macro casts the
pointers into longs before taking the difference of them. This is not
a completely satisfactory solution as the difference should indicate
the number of objects between pointers, not just the number of bytes.

We are fed up with this sort of compiler and now have two compilers
on our MC68000-system. One compiler has 16-bit ints the other has 32-bit
ints. The 16-bit compiler can be used for showing of benchmarks, the 32-bit
is useful for porting programs to the MC68000.

Use of the 32-bit compiler requires that one links the programs not with
libc but a modified version of libc with rewritten systemcalls. That is:
the routine write.s which traps to the write system call must be changed
to take account of the fact that it's arguments are
	write(32-bit, (char *), 32-bit);
whereas the system expects
	write(16-bit, (char *), 16-bit);

{decvax,philabs}!mcvax!enea!ttds!johanw         Johan Widen

keesan@bbncca.ARPA (Morris Keesan) (03/09/84)

----------------------------
ok@edai complains:
>	#include <stdio.h>		/* defines NULL */
>	typedef long **ptr;
>	ptr foo;
>	baz(x)
>	    ptr x;
>	    {...}
>	... baz(NULL); ... foo = NULL; ... baz(foo); ...
>
>   Lint is perfectly happy with foo = NULL;  but  complains  about  the
>   "inconsistent  usage"  of  baz's first argument.  Given that K&R say
>   that 0 is an acceptable pointer of any type, I don't  find  this  at
>   all  helpful.

    Lint is behaving in a perfectly legitimate way here, and is being very
helpful in pointing out a portability problem.

    We've been through all of this very recently in this newsgroup.  K&R do
NOT say that "0 is an acceptable pointer".  What is said about 0 and pointers
in the C Reference Manual (Appendix A of K&R) is:

    7.7 Equality operators [p. 190]
	. . . A pointer to which 0 has been assigned is guaranteed not to
    point to any object, and will APPEAR to be equal to 0; in conventional
    usage, such a pointer is considered to be null. [UPPER CASE mine]
    [This means that 0 can act like a pointer with the == and != operators]

    7.14 Assignment operators [p. 192]
	. . . it is guaranteed that assignment of the constant 0 to a pointer
    will produce a null pointer distinguishable from a pointer to any object.

    [end of citations from Reference Manual]

    What you should be doing to shut lint up is casting NULL to the right type
of pointer, e.g.

	baz((ptr)NULL);

If you don't want to do this, then you want features added to lint by which you
can declare something like /* COMPATIBLE int ptr */, which would document the
assumption being made, or you could define NULL as ((char *)0), and then issue
an /*ALIGNOK *ptr char*/ as per your following suggestion.
-- 
					Morris M. Keesan
					{decvax,linus,wjh12,ima}!bbncca!keesan
					keesan @ BBN-UNIX.ARPA