[comp.lang.c] A lint question

logan@vsedev.VSE.COM (James Logan III) (11/28/88)

I am having a problem with lint that I'm sure you have all seen
before.  I have 3 calls to the read() function and one call to
malloc() which are all used in the same way (same number and type
of arguments), yet lint has this complaint:  

function argument ( number ) used inconsistently
    malloc( arg 1 )   	llib-lc(338) :: findlinks.c(114)
    read( arg 3 )   	llib-lc(104) :: findlinks.c(127)

I assume that lint is telling me that I am calling malloc() and
read() with an inconsistent number or parameters.  How can I be
inconsistent with the number of parameters with one call to
malloc()?  The calls look like this:  

extern char *malloc();
char *directory;
directory = (char *)malloc((int)stbuf.st_size);

if (read(fd, directory, (int)stbuf.st_size) != (int)stbuf.st_size) {
	.
	.
	.
}
while (read(fd, &mntbuf, sizeof(MNT)) == sizeof(MNT)) {
	.
	.
	.
}
while (read(fd, nextentry, sizeof(nextentry)) == sizeof(nextentry)) {
	.
	.
	.
}

They look pretty consistent to me, especially in the argument
count!  Any help would be appreciated.  Thanks in advance.  

			-Jim
-- 
Jim Logan		logan@vsedev.vse.com
(703) 892-0002		uucp:	..!uunet!vsedev!logan
			inet:	logan%vsedev.vse.com@uunet.uu.net

dhesi@bsu-cs.UUCP (Rahul Dhesi) (11/29/88)

In article <1256@vsedev.VSE.COM> logan@vsedev.VSE.COM (James Logan III)
writes:
>function argument ( number ) used inconsistently
>    malloc( arg 1 )   	llib-lc(338) :: findlinks.c(114)
>    read( arg 3 )   	llib-lc(104) :: findlinks.c(127)

Perhaps your lint library declares the argument to malloc, and the
third argument to read, as unsigned, while you declare them as int.

(Sigh.)  You can't always make the same code lint properly under both
SVR2 and 4.3BSD because of this.  Damned if I do, unsigned if I don't.
-- 
Rahul Dhesi         UUCP:  <backbones>!{iuvax,pur-ee}!bsu-cs!dhesi

edf@rocky2.rockefeller.edu (David MacKenzie) (11/29/88)

In article <1256@vsedev.VSE.COM> logan@vsedev.VSE.COM (James Logan III) writes:
>I am having a problem with lint that I'm sure you have all seen
>before.  I have 3 calls to the read() function and one call to
>malloc() which are all used in the same way (same number and type
>of arguments), yet lint has this complaint:  
>
>function argument ( number ) used inconsistently
>    malloc( arg 1 )   	llib-lc(338) :: findlinks.c(114)
>    read( arg 3 )   	llib-lc(104) :: findlinks.c(127)
>
>I assume that lint is telling me that I am calling malloc() and
>read() with an inconsistent number or parameters.  How can I be

Actually, the "( number )" is just the column heading for the "arg n"
fields.  It means that argument number 1 was used inconsistently in with
how it was defined in the lint library for malloc, and argument number
3 was used inconsistently in read.  If you had called it with an
inconsistent number of parameters, that comes under a different heading
in the lint output, "function called with variable number of
arguments".
-----
David MacKenzie
Environmental Defense Fund
edf@rocky2.rockefeller.edu (...rutgers!cmcl2!rocky2!edf)

ok@quintus.uucp (Richard A. O'Keefe) (11/29/88)

In article <1256@vsedev.VSE.COM> logan@vsedev.VSE.COM (James Logan III) writes:
>function argument ( number ) used inconsistently
>    malloc( arg 1 )   	llib-lc(338) :: findlinks.c(114)
>    read( arg 3 )   	llib-lc(104) :: findlinks.c(127)
>I assume that lint is telling me that I am calling malloc() and
>read() with an inconsistent number or parameters.

Nope.  Read that as "either a function argument has the wrong type,
or the function has the wrong number of arguments".
>extern char *malloc();
>char *directory;
>directory = (char *)malloc((int)stbuf.st_size);
			     ^^^^^^^^^^^^^^^^^
	extern char *malloc(size_t howmuch);
size_t is an unsigned integral type (except in BSD systems, where it's "int").

>if (read(fd, directory, (int)stbuf.st_size) != (int)stbuf.st_size) {
    			 ^^^^^^^^^^^^^^^^^^
	extern int read(int fd, char *buffer, size_t howmuch);

>while (read(fd, &mntbuf, sizeof(MNT)) == sizeof(MNT)) {
		 ^^^^^^^
&mntbuf cannot be of type char* unless mntbuf is a single char.
I'm assuming here that mntbuf is some sort of record; in that case you want
	read(fd, (char*)&mntbuf, sizeof mntbuf),
not that lint will like that either.

gwyn@smoke.BRL.MIL (Doug Gwyn ) (11/29/88)

In article <1256@vsedev.VSE.COM> logan@vsedev.VSE.COM (James Logan III) writes:
>function argument ( number ) used inconsistently
>    malloc( arg 1 )   	llib-lc(338) :: findlinks.c(114)
>    read( arg 3 )   	llib-lc(104) :: findlinks.c(127)
>I assume that lint is telling me that I am calling malloc() and
>read() with an inconsistent number or parameters.  How can I be
>inconsistent with the number of parameters with one call to malloc()?

If you look closely, you can see that "lint" is telling you that
the usage on line 114 of findlinks.c is inconsistent with line 338
of llib-lc.  the latter is the "lint library" that defines the
expected types for system interfaces.

>directory = (char *)malloc((int)stbuf.st_size);

char *malloc(unsigned) according to the lint library.

>if (read(fd, directory, (int)stbuf.st_size) != (int)stbuf.st_size) {
>while (read(fd, &mntbuf, sizeof(MNT)) == sizeof(MNT)) {
>while (read(fd, nextentry, sizeof(nextentry)) == sizeof(nextentry)) {

int read(int, char *, unsigned) according to the lint library.
Case 1 has int for argument 3
Case 2 has the wrong pointer type for argument 2
Case 3 is a bug unless nextentry is a char[].

guy@auspex.UUCP (Guy Harris) (11/30/88)

>function argument ( number ) used inconsistently
>    malloc( arg 1 )   	llib-lc(338) :: findlinks.c(114)
>    read( arg 3 )   	llib-lc(104) :: findlinks.c(127)
>
>I assume that lint is telling me that I am calling malloc() and
>read() with an inconsistent number or parameters.  How can I be
>inconsistent with the number of parameters with one call to
>malloc()?

Easy.  Note that the complaint lists file "llib-lc", line 338, and file
"findlinks.c", line 114.  I presume "findlinks.c", line 114, is

>directory = (char *)malloc((int)stbuf.st_size);

On my system, the relevant line in "llib-lc" is

	char *	malloc(n) unsigned n; {static char c; return(&c);}

Note the "unsigned n".  It's probably an "unsigned" on your machine as
well.

"function argument ... used inconsistently" means there are two places
that don't agree on the type of the function argument; one of those
places may be the *definition* of the function.  For system libraries,
the "definition" for the benefit of "lint" appears in a "lint library",
which is generally either located in "/usr/lib" or "/usr/lib/lint".

In your case, while there was only one *call* to "malloc", there was a
*definition* in either "/usr/lib/llib-lc" or "/usr/lib/lint/llib-lc",
and they did not agree.

In C implementations, "malloc" generally takes an "unsigned int" as its
argument, not an "int".  I think the current dpANS specifies this as
well.

As for the calls to "read":

>They look pretty consistent to me, especially in the argument
>count!

It is necessary, but not sufficient, that the argument count be the same
(in the case of functions whose definition is preceded with a
/*VARARGS*/-type comment, it isn't even necessary; this permits "lint"
to, for example, check that the first argument to "printf" is a "char *"
but not check the other arguments).  Let's look at the calls:

>if (read(fd, directory, (int)stbuf.st_size) != (int)stbuf.st_size) {
>	.
>	.
>	.
>while (read(fd, &mntbuf, sizeof(MNT)) == sizeof(MNT)) {
>	.
>	.
>	.
>}
>while (read(fd, nextentry, sizeof(nextentry)) == sizeof(nextentry)) {

The second argument to "read", under UNIX, is supposed to be a "char *".
"directory" is (as declared) a "char *"; however, "mntbuf" may not be a
"char", in which case "&mntbuf" may not be a "char *", and "nextentry"
may be neither a "char *" nor a "char []".  If you pass something other
than a "char *" to "read" as its second argument,

	1) Make sure you're not doing something wrong - for instance,
	   the following is wrong:

		int answer;

		(put terminal into character-at-a-time mode)
		(void) printf("Erase disk? (y or n) ");
		read(0, &answer, 1);
		if (answer == 'y')
			erase();

	   In this particular case, you want to read a single character;
	   this code will do so, but it won't necessarily put it where
	   you expect it to.  There's no guarantee that if the user
	   types a "y", the value left in "answer" after the "read" will
	   be a "y".

	2) Once you're sure you're doing the right thing, cast the
	   pointer in question to "char *":

		while (read(fd, (char *)&mntbuf, sizeof(MNT)) == sizeof(MNT)) {

The *third* argument to "read" is, in POSIX, an "unsigned int", as I
remember.  It may be an "int" in some current UNIX implementations. 
Again, check your documentation and your "/usr/lib/llib-lc" or
"/usr/lib/lint/llib-lc".

If it's an "int", the problem may be with the "sizeof"s.  In more recent
C compilers, the type of the result of "sizeof" is "unsigned int".  If
so, they should be cast to "int" (if, that is, the third argument to
"read" is supposed to be "int").

If it's an "unsigned int", the problem should be obvious....

paul@devon.UUCP (Paul Sutcliffe Jr.) (12/04/88)

In article <4881@bsu-cs.UUCP> dhesi@bsu-cs.UUCP (Rahul Dhesi) writes:
+---------
| [ size argument to malloc/read is (int) on BSD, (unsigned int) on SysV ]
| 
| (Sigh.)  You can't always make the same code lint properly under both
| SVR2 and 4.3BSD because of this.  Damned if I do, unsigned if I don't.
+---------

Oh?  How about:

    #ifdef BSD
    #define SIZE    int
    #else
    #define SIZE    unsigned int
    #endif

    ...

    foo = malloc((SIZE)bar);

    ...

I realize that using the word SIZE may not be appropriate.  If you
agree with this, substitute your favorite word in its place.

- paul

-- 
Paul Sutcliffe, Jr.			  +---------------------------------+
					  | Light Year, n.:  A regular year |
UUCP: paul@devon.UUCP			  |   that has 1/3 less calories.   |
 or : ...rutgers!bpa!vu-vlsi!devon!paul	  +---------------------------------+

dhesi@bsu-cs.UUCP (Rahul Dhesi) (12/06/88)

I said:
     (Sigh.)  You can't always make the same code lint properly under
     both SVR2 and 4.3BSD because of this.  Damned if I do, unsigned if
     I don't.

In article <1165@devon.UUCP> paul@devon.UUCP (Paul Sutcliffe Jr.) writes:
>    #ifdef BSD
>    #define SIZE    int
>    #else
>    #define SIZE    unsigned int
>    #endif

Well, let's respond to this note of despair:

     (Sigh.)  You can't always make the same code compile properly
     under both C and Pascal.

Sure you can:

     #ifdef LANG_C
     ... C code ...
     #else /* LANG_PASCAL */
     ... Pascal code ...
     #endif

Now we just run this through a preprocessor (of which there are plenty,
some free, others copylefted, and one in /lib/cpp) before submitting it
to our favorite compiler.  The question still remains:  are we
compiling the same code, or different code?
-- 
Rahul Dhesi         UUCP:  <backbones>!{iuvax,pur-ee}!bsu-cs!dhesi