Bugtraq mailing list archives

Re: StackGuard with ... Re: [Paper] Format bugs.


From: "Stephen J. Friedl" <friedl () MTNDEW COM>
Date: Sat, 22 Jul 2000 16:21:08 -0700

At 10:48 PM 7/21/2000 -0600, it was written:
Which brings up a more interesting question:

Don't these errors really reflect more fundamental problems in the
development tools?

I believe that this reflects on the programmers and not on the language.
Yes, C permits variadic parameters and doesn't check them very well, but
after nearly 30 years I think it's pointless to argue that C should be
different. This is a fact of life, and the smart developers will Find A Way
to get along with the language facing them.

The first thing to do is turn on the damn compiler warnings, because more
and more compilers actually do check printf-like parameters for you. GNU C
does this, as do numerous commercial compilers:

        $ cat test.c
        #include <stdio.h>

        int main(void)
        {
                printf("i = %d\n");             <--- missing parameter!
        }

        $ gcc test.c
        $                       <-- note: all quiet

        $ gcc -Wall test.c      <-- try again with real warnings
        test.c: In function `main':
        test.c:5: warning: too few arguments for format

Well how about that! It also notices type mismatches, and it works for all
the printf-like and scanf-like functions also. You can use the GNU
__attribute__() facility to attach these qualifiers to your own function,
and the GNU people did this in a way that you can make it work even for
non-GNU compilers:

        /* in header.h */

        #ifndef __GNUC__
        #  define       __attribute__(x)        /*nothing*/
        #endif

        extern void logprintf(const char *format, ...)
__attribute__((format(printf,1,2)));
        extern void logprintva(const char *format, va_list args)
__attribute__((format(printf,1,0)));

The "format" attribute takes either "printf" or "scanf", and the numbers
that follow are the parameter number of the format string and the first
variadic parameter (respectively). The GNU docs talk about this well, and
there are other __attribute__ facilities as well, such as "noreturn" and
"const".

There are also commercial code-inspection tools like PC-Lint that pick
unbelievable tiny bugs from a program, and they have caught many, many
errors in my own code by being more anal-retentive than I could ever be.
For less than $300 I can't imagine developing anything beyond "hello,
world" without it, much less anything where security was important.
http://www.gimpel.com.

The latter problem can be solved by insisting upon the use of macros
that mandate a minimum number of arguments and produce a warning
or error message otherwise.

Function prototypes can solve much of this problem but I am always amazed
at the lengths that programmers go in neutering their effectiveness. This
is just dumb coding:

        /* file1.c */

        int myfunction(int param1, int param2)
        {
                /* do something */
        }

        /* file2.c */

        extern int myfunction(int);             <-- note mismatch!

Here the prototypes don't help because you've not told the truth: Henry
Spencer has said that if you lie to the compiler, it will get its revenge.
Much smarter is to put /every/ prototype in a header file and insist that
every declaration (the "extern") collides with the definition (the real
code body). This way an incorrect prototype is caught by the compiler right
away and these prototype mismatches don't surprise you. I never ever put an
"extern" prototype in a dot-c file. Ever.

Sorry if this turned into comp.lang.c.

Steve
Stephen J. Friedl / Software Consultant / Tustin, CA / 714-544-6561


Current thread: