The canonical clc malloc idiom

Discussion in 'C Programming' started by Keith Thompson, Sep 20, 2007.

  1. The comp.lang.c-recommended way to invoke malloc() is, of course:

    some_type *ptr;
    ptr = malloc(count * sizeof *ptr);

    But what if (in C99 only) ptr is a pointer to a VLA (variable-length
    array) type? Consider this:

    #include <stdio.h>
    #include <stdlib.h>
    int main(void)
    {
    int n = 10;
    typedef char VLA[n];
    VLA *ptr = NULL;
    ptr = malloc(3 * sizeof *ptr);
    printf("sizeof *ptr = %d\n", (int)sizeof *ptr);
    return 0;
    }

    As far as I can tell, this is legal in C99. The operand of sizeof in
    the malloc call is *ptr, which is of a variable-length array type,
    which means, according to C99 6.5.3.4p2, that it's evaluated. Since
    ptr is a null pointer at that point, evaluating *ptr invokes undefined
    behavior.

    I'm not suggesting that we should drop the clc-approved method for the
    normal case; I suspect that malloc calls involving VLA types are going
    to be vanishingly rare. It's just an interesting quirk of the
    language.

    Incidentally, the above program compiles and executes without error
    under gcc in its C99ish mode. That doesn't prove anything, since it's
    one possible consequence of UB.

    I think I'll post in comp.std.c asking just what C99 6.5.3.4p2 really
    means and why the operand is evaluated.

    --
    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."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Sep 20, 2007
    #1
    1. Advertising

  2. On Wed, 19 Sep 2007 21:20:17 -0700, Keith Thompson wrote:

    > The comp.lang.c-recommended way to invoke malloc() is, of course:
    >
    > some_type *ptr;
    > ptr = malloc(count * sizeof *ptr);
    >
    > But what if (in C99 only) ptr is a pointer to a VLA (variable-length
    > array) type? Consider this:
    >
    > #include <stdio.h>
    > #include <stdlib.h>
    > int main(void)
    > {
    > int n = 10;
    > typedef char VLA[n];
    > VLA *ptr = NULL;
    > ptr = malloc(3 * sizeof *ptr);
    > printf("sizeof *ptr = %d\n", (int)sizeof *ptr);
    > return 0;
    > }
    >
    > As far as I can tell, this is legal in C99. The operand of sizeof in
    > the malloc call is *ptr, which is of a variable-length array type,
    > which means, according to C99 6.5.3.4p2, that it's evaluated. Since
    > ptr is a null pointer at that point, evaluating *ptr invokes undefined
    > behavior.
    >
    > I'm not suggesting that we should drop the clc-approved method for the
    > normal case; I suspect that malloc calls involving VLA types are going
    > to be vanishingly rare. It's just an interesting quirk of the
    > language.
    >
    > Incidentally, the above program compiles and executes without error
    > under gcc in its C99ish mode. That doesn't prove anything, since it's
    > one possible consequence of UB.
    >
    > I think I'll post in comp.std.c asking just what C99 6.5.3.4p2 really
    > means and why the operand is evaluated.


    And why the restriction to variable length array types?
    Again with c99ish gcc this compiles and appears to run correctly:
    #include <stdlib.h>
    #include <stdio.h>
    int main( int argc, char** argv)
    {
    struct odd
    { int b;
    int a[argc];
    };
    struct odd* p;
    printf( "sizeof odd %d\n", sizeof *p);
    return EXIT_SUCCESS;
    }
    I'd have thought that if "evaluation" was required for your ptr, it would
    be required for my p too.
     
    Duncan Muirhead, Sep 20, 2007
    #2
    1. Advertising

  3. Keith Thompson

    Army1987 Guest

    On Wed, 19 Sep 2007 21:20:17 -0700, Keith Thompson wrote:

    > The comp.lang.c-recommended way to invoke malloc() is, of course:
    >
    > some_type *ptr;
    > ptr = malloc(count * sizeof *ptr);
    >
    > But what if (in C99 only) ptr is a pointer to a VLA (variable-length
    > array) type? Consider this:
    >
    > #include <stdio.h>
    > #include <stdlib.h>
    > int main(void)
    > {
    > int n = 10;
    > typedef char VLA[n];
    > VLA *ptr = NULL;
    > ptr = malloc(3 * sizeof *ptr);
    > printf("sizeof *ptr = %d\n", (int)sizeof *ptr);
    > return 0;
    > }
    >
    > As far as I can tell, this is legal in C99. The operand of sizeof in
    > the malloc call is *ptr, which is of a variable-length array type,
    > which means, according to C99 6.5.3.4p2, that it's evaluated. Since
    > ptr is a null pointer at that point, evaluating *ptr invokes undefined
    > behavior.
    >
    > I'm not suggesting that we should drop the clc-approved method for the
    > normal case; I suspect that malloc calls involving VLA types are going
    > to be vanishingly rare. It's just an interesting quirk of the
    > language.
    >
    > Incidentally, the above program compiles and executes without error
    > under gcc in its C99ish mode. That doesn't prove anything, since it's
    > one possible consequence of UB.

    But it is a strong clue that it doesn't actually read from *ptr,
    since that would be likely to cause a SIGSEGV. I tried declaring
    ptr as volatile VLA *, but it still doesn't crash. Whereas the UB
    allows it not to actually read from there, the compiler would need
    to do a serious amount of language lawyering to behave like that.
    A more likely explanation is in http://gcc.gnu.org/c99status.html,
    where the support for VLAs is marked as "Broken".

    In the C99 rationale I can read:
    Side effects in variable length array size expressions are guaranteed to be produced, except in
    one context. If a size expression is part of the operand of a sizeof operator, and the result of
    that sizeof operator does not depend on the value of the size expression, then it is unspecified
    10 whether side effects are produced. In the following example:
    {
    int n = 5;
    int m = 7;
    size_t sz = sizeof(int (*)[n++]);
    15 }
    the value of the result of the sizeof operator is the same as in:
    {
    int n = 5;
    int m = 7;
    20 size_t sz = sizeof(int (*)[m++]);
    }
    Since the value stored in sz does not depend on the size expression, the side effect in n++ is
    not guaranteed to occur. Requiring the side effect introduced a burden on some
    implementations. Since side effects in this context seemed to have limited utility and are not
    25 perceived to be a desired coding style, the Committee decided to make it unspecified whether
    these size expressions are actually evaluated.

    IOW, "don't do that".
    --
    Army1987 (Replace "NOSPAM" with "email")
    If you're sending e-mail from a Windows machine, turn off Microsoft's
    stupid “Smart Quotes†feature. This is so you'll avoid sprinkling garbage
    characters through your mail. -- Eric S. Raymond and Rick Moen
     
    Army1987, Sep 20, 2007
    #3
  4. Duncan Muirhead <> writes:
    > On Wed, 19 Sep 2007 21:20:17 -0700, Keith Thompson wrote:

    [...]
    >> I think I'll post in comp.std.c asking just what C99 6.5.3.4p2 really
    >> means and why the operand is evaluated.

    >
    > And why the restriction to variable length array types?
    > Again with c99ish gcc this compiles and appears to run correctly:
    > #include <stdlib.h>
    > #include <stdio.h>
    > int main( int argc, char** argv)
    > {
    > struct odd
    > { int b;
    > int a[argc];
    > };
    > struct odd* p;
    > printf( "sizeof odd %d\n", sizeof *p);
    > return EXIT_SUCCESS;
    > }
    > I'd have thought that if "evaluation" was required for your ptr, it would
    > be required for my p too.


    Yes, that looks like another flaw. I'll post to comp.std.c again.

    --
    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."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Sep 20, 2007
    #4
  5. On Thu, 20 Sep 2007 11:18:25 -0700, Keith Thompson wrote:
    > Duncan Muirhead <> writes:
    >> On Wed, 19 Sep 2007 21:20:17 -0700, Keith Thompson wrote:

    > [...]
    >>> I think I'll post in comp.std.c asking just what C99 6.5.3.4p2 really
    >>> means and why the operand is evaluated.

    >>
    >> And why the restriction to variable length array types? Again with
    >> c99ish gcc this compiles and appears to run correctly: #include
    >> <stdlib.h>
    >> #include <stdio.h>
    >> int main( int argc, char** argv)
    >> {
    >> struct odd
    >> { int b;
    >> int a[argc];
    >> };
    >> struct odd* p;
    >> printf( "sizeof odd %d\n", sizeof *p); return EXIT_SUCCESS;
    >> }
    >> I'd have thought that if "evaluation" was required for your ptr, it
    >> would be required for my p too.

    >
    > Yes, that looks like another flaw. I'll post to comp.std.c again.


    You're not allowed to have VLA structure members, so there doesn't have
    to be any way for sizeof to deal with VLA structure members. If an
    implementation supports them as an extension, the implementation is also
    allowed to evaluate them as an operand to sizeof, because it won't affect
    any correct program.
     
    =?iso-2022-kr?q?Harald_van_D=0E=29=26=0Fk?=, Sep 20, 2007
    #5
  6. Army1987 <> writes:
    [...]
    > In the C99 rationale I can read:
    > Side effects in variable length array size expressions are
    > guaranteed to be produced, except in one context. If a size
    > expression is part of the operand of a sizeof operator, and the
    > result of that sizeof operator does not depend on the value of
    > the size expression, then it is unspecified 10 whether side
    > effects are produced. In the following example:
    > {
    > int n = 5;
    > int m = 7;
    > size_t sz = sizeof(int (*)[n++]); 15 }
    > the value of the result of the sizeof operator is the same as in:
    > {
    > int n = 5;
    > int m = 7; 20 size_t sz = sizeof(int (*)[m++]);
    > }
    > Since the value stored in sz does not depend on the size
    > expression, the side effect in n++ is not guaranteed to
    > occur. Requiring the side effect introduced a burden on some
    > implementations. Since side effects in this context seemed to have
    > limited utility and are not 25 perceived to be a desired coding
    > style, the Committee decided to make it unspecified whether these
    > size expressions are actually evaluated.
    >
    > IOW, "don't do that".


    I think this is an inconsistency between the Rationale and the
    Standard. According to the standard, it's *not*
    implementation-defined whether the side effect occurs. C99 6.5.3.4p2:

    If the type of the operand is a variable length array type, the
    operand is evaluated; otherwise, the operand is not evaluated and
    the result is an integer constant.

    In the case of

    sizeof(int (*)[m++])

    the operand is a pointer type, not a VLA type, so it's not evaluated
    (assuming that evaluating a type makes sense).

    I don't see anything in the standard that makes evaluation of a sizeof
    operand implementation-defined; either it's evaluated or it isn't.

    --
    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."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Sep 20, 2007
    #6
  7. Duncan Muirhead <> writes:
    [...]
    > And why the restriction to variable length array types?
    > Again with c99ish gcc this compiles and appears to run correctly:
    > #include <stdlib.h>
    > #include <stdio.h>
    > int main( int argc, char** argv)
    > {
    > struct odd
    > { int b;
    > int a[argc];
    > };
    > struct odd* p;
    > printf( "sizeof odd %d\n", sizeof *p);
    > return EXIT_SUCCESS;
    > }
    > I'd have thought that if "evaluation" was required for your ptr, it would
    > be required for my p too.


    Your program contains a constraint violation that gcc is failing to
    diagnose.

    C99 6.7.2.1p8:

    A member of a structure or union may have any object type other
    than a variably modified type.

    (I was almost finished with my comp.std.c post before I noticed this.)

    --
    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."
    -- Antony Jay and Jonathan Lynn, "Yes Minister"
     
    Keith Thompson, Sep 20, 2007
    #7
  8. Keith Thompson

    Flash Gordon Guest

    Keith Thompson wrote, On 20/09/07 20:12:
    > Army1987 <> writes:
    > [...]
    >> In the C99 rationale I can read:
    >> Side effects in variable length array size expressions are
    >> guaranteed to be produced, except in one context. If a size
    >> expression is part of the operand of a sizeof operator, and the
    >> result of that sizeof operator does not depend on the value of
    >> the size expression, then it is unspecified 10 whether side
    >> effects are produced. In the following example:
    >> {
    >> int n = 5;
    >> int m = 7;
    >> size_t sz = sizeof(int (*)[n++]); 15 }
    >> the value of the result of the sizeof operator is the same as in:
    >> {
    >> int n = 5;
    >> int m = 7; 20 size_t sz = sizeof(int (*)[m++]);
    >> }
    >> Since the value stored in sz does not depend on the size
    >> expression, the side effect in n++ is not guaranteed to
    >> occur. Requiring the side effect introduced a burden on some
    >> implementations. Since side effects in this context seemed to have
    >> limited utility and are not 25 perceived to be a desired coding
    >> style, the Committee decided to make it unspecified whether these
    >> size expressions are actually evaluated.
    >>
    >> IOW, "don't do that".

    >
    > I think this is an inconsistency between the Rationale and the
    > Standard. According to the standard, it's *not*
    > implementation-defined whether the side effect occurs. C99 6.5.3.4p2:
    >
    > If the type of the operand is a variable length array type, the
    > operand is evaluated; otherwise, the operand is not evaluated and
    > the result is an integer constant.
    >
    > In the case of
    >
    > sizeof(int (*)[m++])
    >
    > the operand is a pointer type, not a VLA type, so it's not evaluated
    > (assuming that evaluating a type makes sense).
    >
    > I don't see anything in the standard that makes evaluation of a sizeof
    > operand implementation-defined; either it's evaluated or it isn't.


    In N1124 and N1256 you have in 6.7.5.2 para 5:
    If the size is an expression that is not an integer constant
    expression: if it occurs in a declaration at function prototype
    scope, it is treated as if it were replaced by *; otherwise,
    each time it is evaluated it shall have a value greater than zero.
    The size of each instance of a variable length array type does not
    change during its lifetime. Where a size expression is part of the
    operand of a sizeof operator and changing the value of the size
    expression would not affect the result of the operator, it is
    unspecified whether or not the size expression is evaluated.

    which I believe is inconsistent with the paragraph you quoted. So I
    think it is a defect in the standard.

    Since my comment is about the standard itself I've cross-posted to
    comp.std.c
    --
    Flash Gordon
     
    Flash Gordon, Sep 20, 2007
    #8
  9. Keith Thompson

    Jack Klein Guest

    On Thu, 20 Sep 2007 11:00:04 +0100, Duncan Muirhead <>
    wrote in comp.lang.c:

    > On Wed, 19 Sep 2007 21:20:17 -0700, Keith Thompson wrote:
    >
    > > The comp.lang.c-recommended way to invoke malloc() is, of course:
    > >
    > > some_type *ptr;
    > > ptr = malloc(count * sizeof *ptr);
    > >
    > > But what if (in C99 only) ptr is a pointer to a VLA (variable-length
    > > array) type? Consider this:
    > >
    > > #include <stdio.h>
    > > #include <stdlib.h>
    > > int main(void)
    > > {
    > > int n = 10;
    > > typedef char VLA[n];
    > > VLA *ptr = NULL;
    > > ptr = malloc(3 * sizeof *ptr);
    > > printf("sizeof *ptr = %d\n", (int)sizeof *ptr);
    > > return 0;
    > > }
    > >
    > > As far as I can tell, this is legal in C99. The operand of sizeof in
    > > the malloc call is *ptr, which is of a variable-length array type,
    > > which means, according to C99 6.5.3.4p2, that it's evaluated. Since
    > > ptr is a null pointer at that point, evaluating *ptr invokes undefined
    > > behavior.
    > >
    > > I'm not suggesting that we should drop the clc-approved method for the
    > > normal case; I suspect that malloc calls involving VLA types are going
    > > to be vanishingly rare. It's just an interesting quirk of the
    > > language.
    > >
    > > Incidentally, the above program compiles and executes without error
    > > under gcc in its C99ish mode. That doesn't prove anything, since it's
    > > one possible consequence of UB.
    > >
    > > I think I'll post in comp.std.c asking just what C99 6.5.3.4p2 really
    > > means and why the operand is evaluated.

    >
    > And why the restriction to variable length array types?
    > Again with c99ish gcc this compiles and appears to run correctly:
    > #include <stdlib.h>
    > #include <stdio.h>
    > int main( int argc, char** argv)
    > {
    > struct odd
    > { int b;
    > int a[argc];
    > };


    It is not legal for a structure or union to contain a VLA:

    6.7.5 Declarators P3 "A full declarator is a declarator that is not
    part of another declarator. The end of a full declarator is a sequence
    point. If the nested sequence of declarators in a full declarator
    contains a variable length array type, the type specified by the full
    declarator is said to be variably modified."

    6.7.5.2 Array declarators P2 "Only an ordinary identifier (as defined
    in 6.2.3) with both block scope or function prototype scope and no
    linkage shall have a variably modified type. If an identifier is
    declared to be an object with static storage duration, it shall not
    have a variable length array type."

    6.2.3 Name spaces of identifiers P1 "If more than one declaration of
    a particular identifier is visible at any point in a translation unit,
    the syntactic context disambiguates uses that refer to different
    entities.
    Thus, there are separate name spaces for various categories of
    identifiers, as follows:

    — label names (disambiguated by the syntax of the label declaration
    and use);

    — the tags of structures, unions, and enumerations (disambiguated by
    following any of the keywords struct, union, or enum);

    — the members of structures or unions; each structure or union has a
    separate name space for its members (disambiguated by the type of the
    expression used to access the member via the . or -> operator);

    — all other identifiers, called ordinary identifiers (declared in
    ordinary declarators or as enumeration constants)."

    So a structure member, is specifically not allowed to be a VLA,
    because it is not an ordinary identifier.

    Also there is 6.7.2.1 Structure and union specifiers P8 "A member of
    a structure or union may have any object type other than a variably
    102) modified type. In addition, a member may be declared to consist
    of a specified number of bits (including a sign bit, if any). Such a
    member is called a bit-field; its width is preceded by a colon."

    I left the reference to footnote 102 in because that adds "A structure
    or union can not contain a member with a variably modified type
    because member names are not ordinary identifiers as de?ned in 6.2.3."

    > struct odd* p;
    > printf( "sizeof odd %d\n", sizeof *p);
    > return EXIT_SUCCESS;
    > }
    > I'd have thought that if "evaluation" was required for your ptr, it would
    > be required for my p too.


    Unfortunately, you can't draw any conclusions from your code because
    defining a structure with a VLA member produces undefined behavior.

    --
    Jack Klein
    Home: http://JK-Technology.Com
    FAQs for
    comp.lang.c http://c-faq.com/
    comp.lang.c++ http://www.parashift.com/c -faq-lite/
    alt.comp.lang.learn.c-c++
    http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
     
    Jack Klein, Sep 21, 2007
    #9
    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. Richard Chrenko

    canonical or absolute path?

    Richard Chrenko, Jan 23, 2004, in forum: Java
    Replies:
    3
    Views:
    42,379
    Anton Spaans
    Jan 23, 2004
  2. Alex Polite
    Replies:
    17
    Views:
    751
    lyallex
    Jun 8, 2004
  3. Alf P. Steinbach
    Replies:
    1
    Views:
    328
    Adam Aulick
    May 26, 2006
  4. Tim H
    Replies:
    3
    Views:
    1,521
    Tim H
    Mar 17, 2007
  5. Tony

    More posts in clc than in clc++ ?

    Tony, Feb 8, 2009, in forum: C Programming
    Replies:
    6
    Views:
    358
Loading...

Share This Page