Why not realloc(&ptr, ...) and free(&ptr)?

Discussion in 'C Programming' started by James Harris, Aug 5, 2013.

  1. I think you meant (free(p), (p) = NULL) (i.e. a comma rather than a
    semicolon).

    <snip>
     
    Ben Bacarisse, Aug 5, 2013
    #21
    1. Advertisements

  2. James Harris

    Joe Pfeiffer Guest

    That really wouldn't help much: pointer aliasing is extremely common,
    and automatically resetting one pointer to a block would still leave a
    dangling pointer behind. And, of course, there would be a tendency for
    novice programmers to expect all the pointers to a block to have been
    reset, which wouldn't be the case.
     
    Joe Pfeiffer, Aug 5, 2013
    #22
    1. Advertisements

  3. James Harris

    Shao Miller Guest

    I think you're thinking of the subject matter of DR #260, perhaps.

    http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_260.htm
     
    Shao Miller, Aug 5, 2013
    #23
  4. Yeah, that's the one.

    The committee response says, in effect, that the representation of a
    pointer p can change after free(p):

    Values may have any bit-pattern that validly represents them
    and the implementation is free to move between alternate
    representations (for example, it may normalize pointers,
    floating-point representations etc.). In the case of an
    indeterminate value all bit-patterns are valid representations
    and the actual bit-pattern may change without direct action of
    the program.

    The DR mentions the issue that the bytes making up the
    representation are themselves objects, and that the requirement
    that "An object [...] retains its last-stored value throughout its
    lifetime." implies that those bytes cannot change. The response
    seems to ignore that argument.

    On the other hand, I actually like the conclusion. As the DR
    discusses, it permits certain optimizations

    I think I would have preferred to have an explicit normative
    statement added to the standard, saying that objects with
    indeterminate values can have their representations change behind
    the scenes.

    Note that the response applies to more than just objects with
    indeterminate values. If a type has multiple representations for the
    same value, an object's representation can switch between those
    representations -- which changes the values of the unsigned char objects
    that make up its representation. This has implications for the use of
    memcmp() to compare things other than byte arrays.
     
    Keith Thompson, Aug 5, 2013
    #24
  5. Yes. I thought "comma" as I was typing it, but apparently my fingers
    were thinking "semicolon". I'll have to talk to them about that.
     
    Keith Thompson, Aug 5, 2013
    #25
  6. In fact, you will occasionally run across code like that, with the
    (void)s added by someone who has their compiler (or lint) warnings
    turned up a little too high.

    S
     
    Stephen Sprunk, Aug 5, 2013
    #26
  7. James Harris

    Siri Cruise Guest

    You can pass lvalues into defines. Adding a few gnucisms:

    #define malloc(var,n) ({ \
    int n1 = n; var = (malloc)(n1); \
    bool success = var || n1==0; \
    success; \
    })

    #define realloc(var,n) ({ \
    int n1 = n; typeof(var) var1 = (realloc)(var,n1); \
    bool success = var1 || n1==0; \
    if (success) var = var1; \
    success; \
    })

    #define free(var) ( \
    (free)(var), (var = 0) \
    )
     
    Siri Cruise, Aug 6, 2013
    #27
  8. James Harris

    James Kuyper Guest

    True. The program isn't going to waste any time executing that line of
    code, because the compiler is going to spend a completely negligible
    amount of time figuring that it can be dropped. On the other hand, the
    author wasted his time writing that line of code, and others will waste
    time reading it and puzzling over why it's there. I think the waste of
    their time is far more important than the time the compiler will waste.
     
    James Kuyper, Aug 6, 2013
    #28
  9. James Harris

    Shao Miller Guest

    Right. I forgot 'volatile' in there.
     
    Shao Miller, Aug 6, 2013
    #29
  10. James Harris

    James Harris Guest

    In a tiny program that's true but consider that in a large program where the
    pointer is reused as an rval as

    *p

    a bug might not get noticed because that pointer still refers to valid
    memory. The CPU doesn't know that the memory pointed at is unused or has
    been reused so it will carry out the access. Setting the pointer to NULL
    allows the CPU to check that if the pointer is incorrectly used again its
    use will be flagged up. The CPU will do this at absolutely no cost to the
    programmer.

    It is even worse if the pointer was used on the LHS of an assignment as in

    *p = ...

    Then the program has just overwritten some memory that could belong to
    something else. Or it could have overwritten unimportant memory. Or it could
    have overwritten part of a pointer chain.... The key aspect of this is that
    it could have introduced one of the worst kind of bugs to track down: one
    that 1) is intermittent, 2) comes and goes depending on whether the debugger
    is running, or 3) only appears once the code is in production. The effect of
    that *p assignment will be totally dependent on the memory layout.

    All in all, setting the freed pointer to NULL is a small price to pay for
    the security it offers on CPUs which can check such accesses in hardware. Of
    course, if there are any other pointers to within the space they too should
    be set to NULL by the programmer at the right point.

    James
     
    James Harris, Aug 7, 2013
    #30
  11. James Harris

    James Kuyper Guest

    I was talking very specifically about the case given in Shao Miller's
    example above, where the variable's lifetime ends immediately after it
    is set to NULL. I strongly recommend nulling any pointer variable that
    points into a block of allocated memory immediately after free(), if it
    will continue to be used after being nulled. On the other hand, I
    strongly recommend avoiding the creation of such variables. Whenever
    possible (which, in my experience, is fairly frequently), I arrange to
    make sure that pointer objects containing pointers into a piece of
    allocated memory have lifetimes that end immediately after the call to
    free().
     
    James Kuyper, Aug 7, 2013
    #31
  12. James Harris

    Tim Rentsch Guest

    It's a horrendous ruling. I have great respect for people
    on the committee, but the decision in this case shows
    very muddy thinking.
    That's a bogus argument, because it's comparing apples and
    oranges. A code transformation is rightly called an optimization
    only when it preserves program semantics; the examples given
    work only by taking advantage of more relaxed semantics, and
    hence should not be called optimizations. Furthermore there is
    no reason to think the gain of such "optimizations" would
    amount to much - they don't happen very often, and don't
    provide much relative value when they do. The potential
    benefits are way not worth the cost in consistency.
    More muddy thinking. The rule in such cases should be the same
    as for regular representations - the program must behave
    according to the semantics of the abstract machine, with
    optimizations allowed only under the as-if rule. The idea that
    object representations (when stored in an object accessible to
    the program) may sensibly spontaneously change is lunacy.
     
    Tim Rentsch, Aug 8, 2013
    #32
    1. Advertisements

Ask a Question

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

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.