How to check whether malloc has allocated memory properly in case ifmalloc(0) can return valid point

Discussion in 'C Programming' started by Shivanand Kadwadkar, Dec 16, 2010.

  1. i want to check after calling malloc whether allocation is successful
    or not. previously i have done like

    ptr=malloc(size);

    if(ptr==NULL)

    But i came to know malloc can return valid pointer in case if argument
    is zero.

    one solution is

    if(size==0)
    ptr=NULL;
    else
    ptr=malloc(size);

    if you have any other suggestion please welcome.
     
    Shivanand Kadwadkar, Dec 16, 2010
    #1
    1. Advertisements

  2. Shivanand Kadwadkar

    Mark Bluemel Guest

    And that pointer can successfully be passed to free(). And you are
    certain to be able to store at least zero bytes at the location pointed
    to by the pointer, so what's the problem?

    If the issue is that you are likely to call malloc() with an argument of
    zero and then attempt to store data at the address returned, your
    problem is not really with malloc() is it?

    I think it would be useful for you to explain in more detail what
    problem you think you need help with, as I'm not at all clear about that.
     
    Mark Bluemel, Dec 16, 2010
    #2
    1. Advertisements

  3. Shivanand Kadwadkar

    BartC Guest

    One issue might be that, if you call malloc(0) enough times, you can run out
    of memory!
     
    BartC, Dec 16, 2010
    #3
  4. The code could be like this

    employees = malloc(N * sizeof(struct Employee));
    if(!employees)
    goto error_handler;
    memcpy(employees, temparray, N * sizeof(struct Employee));

    the code is correct is malloc() returns non-zero for a zero allocation
    and N == 0 is allowed. It's incoorect is malloc() returns zero in this
    situation.
     
    Malcolm McLean, Dec 16, 2010
    #4
  5. Shivanand Kadwadkar

    Tom St Denis Guest

    if (N) {
    employees = calloc(N, sizeof *employees);
    if(!employees) {
    goto error_handler;
    }
    memcpy(employees, temparray, N * sizeof *employees);
    } else {
    employees = NULL;
    }

    There I both fixed the problem and cleaned up your code, that'll be
    100 shillings please, due net 30.

    Tom
     
    Tom St Denis, Dec 16, 2010
    #5
  6. Shivanand Kadwadkar

    Eric Sosman Guest

    Yes: Just like malloc(N), malloc(0) can return NULL or non-NULL.
    Whichever it returns, though, you must not try to read or store through
    that pointer. If it's NULL, well, you mustn't try to read or store
    through NULL. If it's non-NULL you can read or store anything whose
    size does not exceed the argument value, but since *every* C data type
    is at least one byte wide there is nothing that fits in 0 bytes, hence
    nothing you can safely store in 0 bytes.

    To test for "success" of malloc(N), you could write

    ptr = malloc(N);
    if (ptr == NULL && N > 0) {
    // failure
    } else {
    // "success"
    }

    I put "success" in quotes because of an ambiguity that is meaningless
    in practice: If malloc(0) returns NULL, we cannot tell whether it
    "succeeded" or "failed," but it really doesn't make any difference.
    After this, a simple `if (ptr == NULL)' leaves you with the same
    problem you had to begin with.
    One thing to keep in mind is that this `size' value comes from
    somewhere, and will (presumably) govern what you later try to store
    in the allocated area. If your program can calculate `size' as 0,
    it should also never try to store more than 0 bytes in the allocated
    area -- in which case, all will be well no matter what malloc(0)
    returned.

    Since a 0-byte memory area is mostly useless, you probably should
    not be allocating a large number of them -- if you are, you've most
    likely got a bug somewhere. Usually, 0-byte allocations arise when
    you've got a data structure whose size you adjust up and down as the
    circumstances require. Maybe you're keeping track of employees'
    birthdays using 366 dynamically-allocated blocks, and the only person
    born on February 29 quits: Your program might do

    count[date] -= 1; // making it zero
    Person *tmp = realloc(persons[date], count[date] * size *tmp);
    if (tmp == NULL && count[date] > 0) {
    // Can't delete: Hire him back again!
    } else {
    persons[date] = tmp;
    }

    In situations like this, a 0-byte allocation could be considered
    "normal." But if you're routinely making thousands and thousands of
    0-byte allocations, there's likely something wrong elsewhere.
     
    Eric Sosman, Dec 16, 2010
    #6
  7. IMHO the case when malloc(0) return NULL is more interesting, as there you
    need to adjust the error checking, i.e. not exit the program due to lack of
    memory if size was 0.

    Bye, Jojo
     
    Joachim Schmitz, Dec 16, 2010
    #7
  8. Shivanand Kadwadkar

    Tom St Denis Guest

    Agreed, I can't ever think of a legit use for malloc'ing zero bytes.
    It should return a NULL to trip up [what should be in place] normal
    error detection.
     
    Tom St Denis, Dec 16, 2010
    #8
  9. If possible I would design the program so that `size' is only allowed to
    be a positive number. If it is a library I would simply assert that size
    condition is met (the fail fast strategy).


    /August
     
    August Karlstrom, Dec 16, 2010
    #9
  10. I would be a bit careful with putting stuff at the start of the
    allocated area - if you put e.g. 4 bytes at the start and then
    use the original address + 4 then this may not be properly aligned
    for all possible types. You can be only be sure about that for the
    original address returned by malloc().

    Regards, Jens
     
    Jens Thoms Toerring, Dec 16, 2010
    #10
  11. Shivanand Kadwadkar

    Eric Sosman Guest

    You can do this in your own program if you like, but note that
    malloc(0) itself cannot work this way. If it returns non-NULL, it
    must return a value that is distinct from all the other values it
    has returned (that have not yet been released). That is, malloc(0)
    must satisfy:

    void *p = malloc(0);
    void *q = malloc(0);
    assert (p == NULL || p != q);

    Of course, you can make your wrapper behave as you please -- but
    you can't change the behavior of the underlying malloc().
     
    Eric Sosman, Dec 16, 2010
    #11
  12. Shivanand Kadwadkar

    Eric Sosman Guest

    Careful! This has undefined behavior if malloc(n) returns NULL,
    even if n is zero. See 7.21.1p2 and 7.1.4p1, and note the absence of
    any "explicitly stated otherwise" language in 7.21.2.1.

    In other words: You needn't special-case zero (much), but you
    still need the NULL test.
    In the long-ago days when I used FORTRAN (II and IV), it had
    no construct I'd have described as a "zero-trip loop." Specifically,
    a DO loop always executed its body at least once.
     
    Eric Sosman, Dec 16, 2010
    #12
  13. That is not my point. Of course malloc(0) is stupid, but calculating the
    size of a buffer and then malloc()'ing that is legel, even of the size
    calculation mey result in 0. But in that case chacking malloc() for
    returning NULL is not sufficient for aborting the program, you'd also need
    to check size, either before the malloc (and skip it) or after, but befor
    jumping to the error handling.

    I once had to debug a program, actually 'nm', which aborted with a memory
    error on an objectfile, that, as it turned out later, had 0 symbols (which
    is not usual, but legal), and so 'nm' successfully malloc()'ed 0 bytes, but
    chocked on the NULL check.

    Bye, Jojo
     
    Joachim Schmitz, Dec 16, 2010
    #13
  14. As a memory-block with sizer 0 isn't touched
    you don't need to care for this case explicitly.
     
    Gerald Breuer, Dec 16, 2010
    #14
  15. Shivanand Kadwadkar

    Eric Sosman Guest

    That works. It's silly, IMHO, but it works. (Keep in mind that
    `int' and `size_t' are not synonymous, so you may be inviting trouble
    with your choice of parameter type.)
    Not sure what you mean by "hide." You cannot "hide" it in the
    sense of making it unavailable to other code in the program, nor can
    you "hide" it in the sense of intercepting all malloc() calls and
    routing them somewhere other than to the real malloc(). You can, of
    course, threaten to flog or "hide" or "give a hiding to" anyone who
    calls malloc() directly instead of using your wrapper -- but that's
    social engineering, not software engineering.
     
    Eric Sosman, Dec 16, 2010
    #15
  16. Shivanand Kadwadkar

    Eric Sosman Guest

    The phrase "duck and cover" springs to mind.

    That's not a "zero-trip loop," it's an ordinary loop conditionally
    skipped. (And it still iterates once for n=-42.) (And it's not "very
    early on," because the "logical IF" wasn't in the language prior to
    FORTRAN IV.)
     
    Eric Sosman, Dec 16, 2010
    #16
  17. Shivanand Kadwadkar

    BartC Guest

    Fortran IV came out nearly 50 years ago. How much earlier do you want to go?
     
    BartC, Dec 16, 2010
    #17
  18. Shivanand Kadwadkar

    Eric Sosman Guest

    "Nearly 50 years ago" FORTRAN IV was available on a handful of
    computers. In late 1966 (44 < 50 years ago) I was writing my first
    programs in FORTRAN II.

    Fortran, with its newfangled mixed-case name (note that even C has
    not yet advanced to a mixed-case name), didn't arrive until 1991. By
    then, CALL EXIT was a vanished speck in my personal rear-view mirror.

    FORTRAN (NO SUFFIX) was altogether before my time, though.
     
    Eric Sosman, Dec 17, 2010
    #18
  19. break;
    //> goto error_handler;
    if(N && (employees == NULL))
    {
    do_something_here();
    }
    only 30 shillings, 70 go for the goto :p

    -rasp
     
    Ralph Spitzner, Dec 17, 2010
    #19
  20. Shivanand Kadwadkar

    arnuld Guest

    I tried this and it hanged my system in 60 seconds. Last thing I could
    see from top commnd (Linux) after 40 or so seconds that memory usage was
    jumping between 83-87% range and CPU u]2sage was 13-17% range and then I
    switched to Emacs from urxvt, to look at source code and moved the cursor
    10 lines down and then everything just jammed, had to give a hard reboot.

    If malloc was called 1000,000 times then memory used still is 0 bytes
    (1000,000 * 0 = 0), hence I still wonder when malloc(0) allocates 0 bytes
    why system hanged by eating all memory ?



    /* **** DO NOT TRY to run this code PLEASE ***. It will crash your
    system. */
    #include <stdio.h>
    #include <stdlib.h>

    int main(void)
    {
    char* p;

    while(1)
    {
    p = malloc(0);

    if(NULL == p)
    {
    printf("********* Out of Memory ******** \n");
    break;
    }
    }

    printf("---------------------\n");

    return 0;
    }
     
    arnuld, Dec 20, 2010
    #20
    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.