How to specify a non-null pointer argument in C

Discussion in 'C Programming' started by jacob navia, Jan 20, 2007.

  1. jacob navia

    jacob navia Guest

    Problem

    You want to ensure that a pointer argument to a function
    is non-null.

    Solution

    int fn(double data[static 1]);

    This means that the array (that is passed as a pointer)
    must have at least 1 element, i.e. can't be NULL.

    I wasn't aware of this till a discussion in comp.std.c
    jacob navia, Jan 20, 2007
    #1
    1. Advertising

  2. jacob navia wrote:
    > Problem
    >
    > You want to ensure that a pointer argument to a function
    > is non-null.


    Solution

    Compare the pointer to a null pointer, and don't call the function if
    they compare equal.

    Problem

    You want to assume that a pointer function parameter is non-null.

    > Solution
    >
    > int fn(double data[static 1]);
    >
    > This means that the array (that is passed as a pointer)
    > must have at least 1 element, i.e. can't be NULL.


    This ensures nothing, but allows certain otherwise invalid
    optimisations, which may well be what you wanted. A minor point,
    though:

    #include <stdlib.h>

    void f(double data[static 1]) {}
    void g(double *data) {
    if(data != NULL)
    f(data);
    }

    int main(void) {
    double x;
    g(&x + 1);

    double *p = malloc(1);
    g(p);
    free(p);
    }

    Both potential calls to f would be valid if "static 1" only meant
    "non-null" and nothing more.

    > I wasn't aware of this till a discussion in comp.std.c
    =?utf-8?B?SGFyYWxkIHZhbiBExLNr?=, Jan 20, 2007
    #2
    1. Advertising

  3. jacob navia

    santosh Guest

    jacob navia wrote:
    > Problem
    >
    > You want to ensure that a pointer argument to a function
    > is non-null.
    >
    > Solution
    >
    > int fn(double data[static 1]);
    >
    > This means that the array (that is passed as a pointer)
    > must have at least 1 element, i.e. can't be NULL.
    >
    > I wasn't aware of this till a discussion in comp.std.c


    How's the above to be extrapolated for the general case?

    Isn't simply comparing against NULL a simpler approach?
    santosh, Jan 20, 2007
    #3
  4. jacob navia

    hagman Guest

    jacob navia schrieb:

    > Problem
    >
    > You want to ensure that a pointer argument to a function
    > is non-null.
    >
    > Solution
    >
    > int fn(double data[static 1]);
    >
    > This means that the array (that is passed as a pointer)
    > must have at least 1 element, i.e. can't be NULL.
    >
    > I wasn't aware of this till a discussion in comp.std.c


    In what way then will

    x = fn(p);

    fail if p happens to be NULL?
    hagman, Jan 20, 2007
    #4
  5. jacob navia

    jacob navia Guest

    hagman a écrit :
    > jacob navia schrieb:
    >
    >
    >>Problem
    >>
    >>You want to ensure that a pointer argument to a function
    >>is non-null.
    >>
    >>Solution
    >>
    >>int fn(double data[static 1]);
    >>
    >>This means that the array (that is passed as a pointer)
    >>must have at least 1 element, i.e. can't be NULL.
    >>
    >>I wasn't aware of this till a discussion in comp.std.c

    >
    >
    > In what way then will
    >
    > x = fn(p);
    >
    > fail if p happens to be NULL?
    >


    The compiler can automatically insert a test in a
    debug setting. For instance given this prototype

    int fn(char string[static 1]);

    when seeing a call
    fn(s);
    can replace that with

    assert(s);
    fn(s);

    at each call site!
    jacob navia, Jan 20, 2007
    #5
  6. jacob navia

    jacob navia Guest

    santosh a écrit :
    > jacob navia wrote:
    >
    >>Problem
    >>
    >>You want to ensure that a pointer argument to a function
    >>is non-null.
    >>
    >>Solution
    >>
    >>int fn(double data[static 1]);
    >>
    >>This means that the array (that is passed as a pointer)
    >>must have at least 1 element, i.e. can't be NULL.
    >>
    >>I wasn't aware of this till a discussion in comp.std.c

    >
    >
    > How's the above to be extrapolated for the general case?
    >
    > Isn't simply comparing against NULL a simpler approach?
    >


    Obviously this is for the compiler. In a debug setting, a
    compiler and replace
    fn(s)
    with
    assert(s),fn(s);

    given a prototype
    char *fn(char str[static 1]);
    jacob navia, Jan 20, 2007
    #6
  7. jacob navia

    jacob navia Guest

    Harald van Dijk a écrit :
    > jacob navia wrote:
    >
    >>Problem
    >>
    >>You want to ensure that a pointer argument to a function
    >>is non-null.

    >
    >
    > Solution
    >
    > Compare the pointer to a null pointer, and don't call the function if
    > they compare equal.
    >
    > Problem
    >
    > You want to assume that a pointer function parameter is non-null.
    >
    >
    >>Solution
    >>
    >>int fn(double data[static 1]);
    >>
    >>This means that the array (that is passed as a pointer)
    >>must have at least 1 element, i.e. can't be NULL.

    >
    >
    > This ensures nothing, but allows certain otherwise invalid
    > optimisations, which may well be what you wanted. A minor point,
    > though:
    >
    > #include <stdlib.h>
    >
    > void f(double data[static 1]) {}
    > void g(double *data) {
    > if(data != NULL)
    > f(data);
    > }
    >
    > int main(void) {
    > double x;
    > g(&x + 1);
    >
    > double *p = malloc(1);
    > g(p);
    > free(p);
    > }
    >
    > Both potential calls to f would be valid if "static 1" only meant
    > "non-null" and nothing more.
    >
    >
    >>I wasn't aware of this till a discussion in comp.std.c

    >
    >


    well, you are right. That bug is not catched.
    jacob navia, Jan 20, 2007
    #7
  8. "jacob navia" <> wrote in message
    news:45b1f2a1$0$27402$...
    > Problem
    >
    > You want to ensure that a pointer argument to a function
    > is non-null.
    >
    > Solution
    >
    > int fn(double data[static 1]);
    >
    > This means that the array (that is passed as a pointer)
    > must have at least 1 element, i.e. can't be NULL.
    >
    > I wasn't aware of this till a discussion in comp.std.c


    what do you mean with ensure? I tried this code and I could easily call this
    function with NULL. I didnt get a warning or error at all. And of course
    this only happens at compile time right where the compiler can actually
    analyse that it is called with NULL.

    What about this then?
    fn (malloc(1000000 * sizeof(double));

    Seems to me we're stuck with if (p == NULL) for a while :)
    Serve Laurijssen, Jan 20, 2007
    #8
  9. "hagman" <> writes:
    > jacob navia schrieb:
    > > Problem
    > >
    > > You want to ensure that a pointer argument to a function
    > > is non-null.
    > >
    > > Solution
    > >
    > > int fn(double data[static 1]);
    > >
    > > This means that the array (that is passed as a pointer)
    > > must have at least 1 element, i.e. can't be NULL.
    > >
    > > I wasn't aware of this till a discussion in comp.std.c

    >
    > In what way then will
    >
    > x = fn(p);
    >
    > fail if p happens to be NULL?


    By invoking undefined behavior.

    C99 6.7.5.3p7:

    If the keyword static also appears within the [ and ] of the array
    type derivation, then for each call to the function, the value of
    the corresponding actual argument shall provide access to the
    first element of an array with at least as many elements as
    specified by the size expression.

    This "shall" appears outside a constraint, so if it's violated the
    result is undefined behavior.

    You might as well just (attempt to) dereference the pointer inside the
    function; that invokes UB in exactly the same circumstances. And in
    either case, a compiler may, but is not required to, insert a check
    (and to decide what happens if the check fails).

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
    Keith Thompson, Jan 20, 2007
    #9
  10. jacob navia

    jacob navia Guest

    Serve Laurijssen a écrit :
    > "jacob navia" <> wrote in message
    > news:45b1f2a1$0$27402$...
    >
    >>Problem
    >>
    >>You want to ensure that a pointer argument to a function
    >>is non-null.
    >>
    >>Solution
    >>
    >>int fn(double data[static 1]);
    >>
    >>This means that the array (that is passed as a pointer)
    >>must have at least 1 element, i.e. can't be NULL.
    >>
    >>I wasn't aware of this till a discussion in comp.std.c

    >
    >
    > what do you mean with ensure? I tried this code and I could easily call this
    > function with NULL. I didnt get a warning or error at all. And of course
    > this only happens at compile time right where the compiler can actually
    > analyse that it is called with NULL.
    >
    > What about this then?
    > fn (malloc(1000000 * sizeof(double));
    >
    > Seems to me we're stuck with if (p == NULL) for a while :)
    >
    >

    This would provoke an assertion failure (if malloc returns NULL)

    The compiler would automatically test for NULL *before* pushing the
    arguments. In this case you would have an assertion failed NOT in the
    fn function but in the calling function, where the error actually
    is!

    This is MUCH better than testing for NULL in 'fn'
    jacob navia, Jan 20, 2007
    #10
  11. jacob navia <> writes:
    > Serve Laurijssen a écrit :
    > > "jacob navia" <> wrote in message
    > > news:45b1f2a1$0$27402$...
    > >
    > >>Problem
    > >>
    > >>You want to ensure that a pointer argument to a function
    > >>is non-null.
    > >>
    > >>Solution
    > >>
    > >>int fn(double data[static 1]);
    > >>
    > >>This means that the array (that is passed as a pointer)
    > >>must have at least 1 element, i.e. can't be NULL.
    > >>
    > >>I wasn't aware of this till a discussion in comp.std.c

    > > what do you mean with ensure? I tried this code and I could easily
    > > call this function with NULL. I didnt get a warning or error at
    > > all. And of course this only happens at compile time right where the
    > > compiler can actually analyse that it is called with NULL.
    > > What about this then?
    > > fn (malloc(1000000 * sizeof(double));
    > > Seems to me we're stuck with if (p == NULL) for a while :)

    > This would provoke an assertion failure (if malloc returns NULL)


    What assertion failure? Passing a null pointer to fn() invokes
    undefined behavior; there is *no* required or implied check.

    > The compiler would automatically test for NULL *before* pushing the
    > arguments. In this case you would have an assertion failed NOT in the
    > fn function but in the calling function, where the error actually
    > is!
    >
    > This is MUCH better than testing for NULL in 'fn'


    A compiler *could* perform such a check, but if you want your code to
    be portably robust, your only option is to do the check in your code.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
    Keith Thompson, Jan 21, 2007
    #11
  12. "jacob navia" <> wrote in message
    news:45b20f59$0$5106$...
    >>>This means that the array (that is passed as a pointer)
    >>>must have at least 1 element, i.e. can't be NULL.
    >>>
    >>>I wasn't aware of this till a discussion in comp.std.c

    >>
    >>
    >> How's the above to be extrapolated for the general case?
    >>
    >> Isn't simply comparing against NULL a simpler approach?
    >>

    >
    > Obviously this is for the compiler. In a debug setting, a
    > compiler and replace
    > fn(s)
    > with
    > assert(s),fn(s);
    >
    > given a prototype
    > char *fn(char str[static 1]);


    I agree its somewhat nice that there is a way to express that a pointer may
    not be NULL and that a compiler can insert some assert then, but you just
    cant rely on that all compilers will do this so the progger will have to
    check himself too.
    If you're planning to build this into your compiler, may I suggest that if
    the code contains a manual NULL-pointer check that you omit the assert? :)
    Serve Laurijssen, Jan 21, 2007
    #12
  13. jacob navia

    hagman Guest

    jacob navia schrieb:

    > hagman a écrit :
    > > jacob navia schrieb:
    > >
    > >
    > >>Problem
    > >>
    > >>You want to ensure that a pointer argument to a function
    > >>is non-null.
    > >>
    > >>Solution
    > >>
    > >>int fn(double data[static 1]);
    > >>
    > >>This means that the array (that is passed as a pointer)
    > >>must have at least 1 element, i.e. can't be NULL.
    > >>
    > >>I wasn't aware of this till a discussion in comp.std.c

    > >
    > >
    > > In what way then will
    > >
    > > x = fn(p);
    > >
    > > fail if p happens to be NULL?
    > >

    >
    > The compiler can automatically insert a test in a
    > debug setting. For instance given this prototype
    >
    > int fn(char string[static 1]);
    >
    > when seeing a call
    > fn(s);
    > can replace that with
    >
    > assert(s);
    > fn(s);
    >
    > at each call site!


    Maybe, but then it's at least no compile-time test, but rather a
    runtime test.
    Production code that might die with an "assertion failed: s in line
    ...." (in its debug version)
    is not really more stable than code that dies with a segfault.

    Thus I might as well have used the simpler idiom

    int fn(char* string) {
    assert(string);
    ...
    }

    Also, this is much clearer to me as the "char string[static 1]" trick
    seems to suggest
    to the unalert reader that the size of the array is exactly 1.
    hagman, Jan 21, 2007
    #13
  14. jacob navia

    jacob navia Guest

    hagman a écrit :
    > Maybe, but then it's at least no compile-time test, but rather a
    > runtime test.
    > Production code that might die with an "assertion failed: s in line
    > ..." (in its debug version)
    > is not really more stable than code that dies with a segfault.
    >


    It would crash not in the called function but in the calling function.
    Big difference!
    jacob navia, Jan 21, 2007
    #14
  15. jacob navia <> writes:
    > hagman a écrit :
    > > Maybe, but then it's at least no compile-time test, but rather a
    > > runtime test.
    > > Production code that might die with an "assertion failed: s in line
    > > ..." (in its debug version)
    > > is not really more stable than code that dies with a segfault.
    > >

    >
    > It would crash not in the called function but in the calling function.
    > Big difference!


    jacob, you *do* understand that it's not required to crash at all,
    right? Given:

    int fn(double data[static 1]);

    the compiler is not obliged to insert any check at all.

    --
    Keith Thompson (The_Other_Keith) <http://www.ghoti.net/~kst>
    San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
    We must do something. This is something. Therefore, we must do this.
    Keith Thompson, Jan 21, 2007
    #15
  16. jacob navia

    jacob navia Guest

    Keith Thompson a écrit :
    > jacob navia <> writes:
    >
    >>hagman a écrit :
    >>
    >>>Maybe, but then it's at least no compile-time test, but rather a
    >>>runtime test.
    >>>Production code that might die with an "assertion failed: s in line
    >>>..." (in its debug version)
    >>>is not really more stable than code that dies with a segfault.
    >>>

    >>
    >>It would crash not in the called function but in the calling function.
    >>Big difference!

    >
    >
    > jacob, you *do* understand that it's not required to crash at all,
    > right? Given:
    >
    > int fn(double data[static 1]);
    >
    > the compiler is not obliged to insert any check at all.
    >


    Of course not. But it CAN do it legally.

    This is a great progress, at least for me. I will change all headers
    where the standard has

    size_t strlen(const char *);

    to

    size_t strlen(const char[static 1]);

    and I will insert tests for NULL when calling those functions
    automatically!
    jacob navia, Jan 21, 2007
    #16
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Replies:
    5
    Views:
    26,476
    Mike Schilling
    Mar 29, 2006
  2. Alan Woodland
    Replies:
    12
    Views:
    530
    Marco Manfredini
    Nov 22, 2007
  3. aneuryzma
    Replies:
    3
    Views:
    689
    Jim Langston
    Jun 16, 2008
  4. Kai-Uwe Bux
    Replies:
    13
    Views:
    683
  5. Christopher
    Replies:
    4
    Views:
    424
    Ruben Safir
    Jul 9, 2011
Loading...

Share This Page