Search code examples
clinuxsegmentation-faultmallocnon-deterministic

nondeterministic failures due to incorrect malloc size?


Do we have an example that demonstrates non-deterministic failures due to the incorrect malloc size in C?

For example, in my 'gzip' program in linux:

.
.
.
char* a = (char*)malloc(256) // correct version 
is changed to
char* a = (char*)malloc(206) //faulty version
.
.
.

Because of this, a test case tc that pass on the correct version becomes fail (i.e., segmentation fault) on the faulty version. However, the failure is non-deterministic. Sometimes, the failed test case tc on the faulty version does not cause segmentation fault (i.e., pass).

This may be due to the 'undefined' behavior of malloc, but I could not know how it happens exactly.

Does anyone can give me some concrete example? Thank you in advance.


Solution

  • Imagine the memory as a sequence of pages. Some are available to your process, some are unavailable due to permissions and some are simply inaccessible, i.e. not mapped in. Consider this map (not to scale):

          +                        +   +
          |   Page, 4096 bytes     |   |
          +-----------------+------+   |
          |                 |      |   |
          |                 |      |   |
          |                 |      |   |
          +-----------------+------+-->v
               3890B          206B   X <-- Not mapped, can't touch!
    

    If you allocate 206 bytes it all depends where in the page those 206 bytes will lie.

    • If they lie at the start (to the left) accessing more is OK as far as Linux is concerned (but still undefined behavior as far as C is concerned)

    • If however accessing more bytes spills into another page, with a different protection or into one that's not mapped in, Linux will not be amused and you'll get a segfault

    So you're at the mercy of something you can't control: where malloc will allocate your data, i.e. where the additional 50 bytes will be.