1

I've been interested lately about the behaviour of malloc function in C, and i've observed a interesting behaviour. It looks like the first 'out of bounds' value after a malloc turns out to be NULL (or at least, returns something considered false by if). Here is an illustration :

int main (){

    int i;
    double * d_ptr = malloc (10 * sizeof (double)); //malloc 10 double
    for (i=0 ; i<10 ; i++){                         // initialise them ...
        d_ptr[i] = 42;
    }

    for (i=0 ;i <50 ; i++){ /// loop obviously trying to go out of bounds
        if (d_ptr[i]){
            printf("i=%d,d[%d]=%f\n",i,i,d_ptr[i]);
        }
        else {
            printf("out of bounds : i=%d\n",i);
            break;
        }
    }

    printf("exited 'out of bounds loop' safely\n");
    free(d_ptr);
    return 0;
}

Here's the output :

i=0,d[0]=42.000000
i=1,d[1]=42.000000
i=2,d[2]=42.000000
i=3,d[3]=42.000000
i=4,d[4]=42.000000
i=5,d[5]=42.000000
i=6,d[6]=42.000000
i=7,d[7]=42.000000
i=8,d[8]=42.000000
i=9,d[9]=42.000000
out of bounds : i=10
exited 'out of bounds loop' safely

My questions are :

  • Is this behavior predictable ? I tried a bunch of variable types, differents sizes for the malloc, and i always am exiting the loop safely.

  • If it is predictable, can it become a reliable way to loop on pointers in situation where knowing their 'size' would be tricky, or require lots of rewriting ?

  • And finally, what is the deeper explanation of it ? does malloc allocate one word extra after the memory space it was asked to allocate ?
m.raynal
  • 2,983
  • 2
  • 21
  • 34
  • 3
    Accessing out of bounds is undefined behavior. Anything can happen, it's most definitely not predictable. – Barmar Jan 24 '17 at 21:52
  • Try freeing the memory after you've assigned to it, then allocate a slightly smaller block, and see if you still get `0` at the end of the new block. – Barmar Jan 24 '17 at 21:57

2 Answers2

2

"Is this behavior predictable ?" No, it's undefined. "And finally, what is the deeper explanation of it ? does malloc allocate one word extra after the memory space it was asked to allocate ?" No, at least not in any implementation that I know of, you should never knowingly try to access an array out of bounds or dereference uninitialised data as it will always result in undefined behaviour. You may in some cases get lucky with UB and the program will behave as expected even after it's been invoked, just beware time travelling nasal dragons.

Community
  • 1
  • 1
George
  • 2,101
  • 1
  • 13
  • 27
  • Thanks both for the advice and the time travelling nasal dragons ! Sometimes nothing's better than a nice image to remember a cold fact. – m.raynal Jan 24 '17 at 22:16
2

When you invoke undefined behavior, anything can happen. You program may crash, it may display strange results, or it may appear to work properly. In this case, you got the latter.

Running this program under valgrind gave the following results:

==22701== Memcheck, a memory error detector
==22701== Copyright (C) 2002-2009, and GNU GPL'd, by Julian Seward et al.
==22701== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==22701== Command: /tmp/x1
==22701==
i=0,d[0]=42.000000
i=1,d[1]=42.000000
i=2,d[2]=42.000000
i=3,d[3]=42.000000
i=4,d[4]=42.000000
i=5,d[5]=42.000000
i=6,d[6]=42.000000
i=7,d[7]=42.000000
i=8,d[8]=42.000000
i=9,d[9]=42.000000
==22701== Invalid read of size 8
==22701==    at 0x4005C4: main (x1.c:13)
==22701==  Address 0x4c18090 is 0 bytes after a block of size 80 alloc'd
==22701==    at 0x4A0610C: malloc (vg_replace_malloc.c:195)
==22701==    by 0x400579: main (x1.c:7)
==22701==
out of bounds : i=10
exited 'out of bounds loop' safely
==22701==
==22701== HEAP SUMMARY:
==22701==     in use at exit: 0 bytes in 0 blocks
==22701==   total heap usage: 1 allocs, 1 frees, 80 bytes allocated
==22701==
==22701== All heap blocks were freed -- no leaks are possible
==22701==
==22701== For counts of detected and suppressed errors, rerun with: -v
==22701== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 4 from 4)

As you can see, this was properly recognized as reading past the end of a malloc'ed buffer.

Just because the program can crash doesn't mean it will.

So no, this behavior is not predictable.

dbush
  • 205,898
  • 23
  • 218
  • 273