[comp.unix.programmer] lint

chris@visionware.co.uk (Chris Davies) (05/01/91)

While writing a makefile I came across the following problem with 'lint' on
SysV.3 UNIX (several different flavours of the same).

Consider a simple standalone program hello.c, anything reasonably correct will
do.

    $ cc -DFRED="oneword" -O -s c.c -o c
    $ lint -DFRED="oneword" c.c

OK so far. No problems (both commands work as expected).

Now try defining FRED as "two words", thus

    $ cc -DFRED="two words" -O -s c.c -o c
    $ lint -DFRED="two words" c.c

The compiler does its funky stuff quite happily, and the preprocessor defines
FRED as the constant "two words".

However there is no output from lint on the screen, and what's more, on closer
examination it's apparent that the file "words" (the second word of the
definition for FRED) contains the preprocessor output...

Why?

Chris
-- 
         VISIONWARE LTD, 57 Cardigan Lane, LEEDS LS4 2LE, England
    Tel +44 532 788858.  Fax +44 532 304676.  Email chris@visionware.co.uk
-------------- "VisionWare:   The home of DOS/UNIX/X integration" -------------

scs@adam.mit.edu (Steve Summit) (05/07/91)

In article <1991May1.145501.1752@visionware.co.uk> chris@visionware.co.uk (Chris Davies) writes:
>Now try defining FRED as "two words", thus
>
>    $ lint -DFRED="two words" c.c
>
>However there is no output from lint on the screen, and what's more, on closer
>examination it's apparent that the file "words" (the second word of the
>definition for FRED) contains the preprocessor output...

lint is typically implemented as a shell script which invokes the
preprocessor and the "passes" of lint proper.  (Once upon a time,
the cc driver was a shell script, too.)  The big disadvantage of
implementing a command like this as a shell script is that
there's another chance for quoting to be stripped off.  Somewhere
in the lint shell script is an invocation of cpp, something like:

	$CPP $infile $cppflags | $lint1

The $cppflags variable contains those flags you handed to lint
which should he handed to cpp (namely -D, -U, and -I).  You can
see that without some kind of very special handling, your quoted
two-word definition, when re-examined on the cpp invocation line
within the lint shell script, will be interpreted as two words.
Unfortunately, putting the $cppflags interpolation in quotes:

	$CPP $infile "$cppflags" | $lint1

would make things worse, because $cppflags may contain several
-D's, -U's, and/or -I's, which should be interpreted as several
words.  (It probably also contains -C and -Dlint .)

Anyway, what happens is that "words" ends up looking like a
second non-flag argument to cpp, which it treats as an output
file.  (I have to assume from your reported symptoms that your
lint shell script invokes cpp as

	$CPP $infile $cppflags

rather than the more conventional

	$CPP $cppflags $infile

since otherwise "words" would have been assumed to be an input
file, and there would have been a risk of overwriting your source
file, since it would be treated as the output file.  I can't
verify any of this, because the lint script on this BSD system is
apparently different, as it fails in different ways on your
example.  However, I do note that cpp, even here, will accept
flag arguments after the input file, which is a bit unusual given
the simpleminded argv parse most C/Unix programs perform.)

It's nearly impossible to write a shell script that does the kind
of production-quality argument parse, including quoting, that
lint potentially requires to handle cases like this (which aren't
unheard of).  Somebody gets an "A" for good intentions for having
tried, but it would not be out of the question to rewrite the
lint driver as a simple C program one of these days.  (I've seen
a number of other obscure lint argument parsing bugs which
resulted from its shell script implementation.)

                                            Steve Summit
                                            scs@adam.mit.edu