#1
  1. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2012
    Posts
    4
    Rep Power
    0

    Malloc strangeness


    I've been focusing on C lately, coming from languages based on C has helped alot. Now, C is at times surprisingly simple and yet sometimes surprisingly devilish. So far I've learned that attention to the finer works of C can help improve my understanding.

    I am experimenting on a FreeBSD 9.1 environment

    However, I have come across a field where the reasoning makes sense, but practical examples and tests seems to throw me for a loop, and I don't really know where to go for help.

    The culprit? Malloc.

    Everywhere I read, malloc should allocate the amount of memory you need for a particular need, like house a char *var or a struct or the like.

    As such

    PHP Code:
    myStructPtr = (myStruct *)malloc(sizeof(myStruct)); 
    Makes good sense. There seems to be a debate as to whether the (myStruct *) explicit cast is nice C or bad C.

    Now, here's where things start to get to me.
    Consider the following utterly contrieved example.


    PHP Code:
    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>

    int main(void) {
        
    char *ptr "supposedly the universe is infinitely large, the sheer size makes my head ache!";
        
    char *malloc(10 sizeof(char));
        
    char *malloc(sizeof(char));
        
    char *malloc(10 sizeof(char));
        
    char *malloc(sizeof(char));
        
    char *malloc(strlen(ptr) * sizeof(char));

        
    printf("sizeof(char) = %d\n"sizeof(char));
        
    printf("ptr = %s\n"ptr);
        
    printf("a = 0x%X -> malloc(10)\n", &a);
        
    printf("b = 0x%X -> malloc(0)\n", &b);
        
    printf("c = 0x%X -> malloc(10)\n", &c);
        
    printf("d = 0x%X -> malloc(2)\n", &d);
        
    printf("e = 0x%X -> malloc(strlen(ptr) * sizeof(char))\n", &e);

        
    printf("a = %i\n"a);
        
    printf("b = %i\n"b);
        
    printf("c = %i\n"c);
        
    printf("d = %i\n"d);
        
    printf("e = %i\n"e);

        
    strcpy(aptr);
        
    strcpy(bptr);
        
    strcpy(cptr);
        
    strcpy(dptr);
        
    strcpy(eptr);

        
    printf("a = %s\n"a);
        
    printf("b = %s\n"b);
        
    printf("c = %s\n"c);
        
    printf("d = %s\n"d);
        
    printf("e = %s\n"e);
        return 
    0;

    Look at the mallocs. I deliberately allocate less-than-required memory for the a, b, c and d pointers before filling them with the contents of the ptr pointer. The e pointer is malloc'd as I've learned to do.

    As for b, which essentially is malloc(0), it seems to be implementation dependant and can even be undefined behaviour.

    When this code is compiled and run on my playground, the strings a and b looks very weird while c, d and e looks normally.

    Code:
    sizeof(char) = 1
    ptr = supposedly the universe is infinitely large, the sheer size makes my head ache!
    a = 0xBFBFEC8C -> malloc(10)
    b = 0xBFBFEC88 -> malloc(0)
    c = 0xBFBFEC84 -> malloc(10)
    d = 0xBFBFEC80 -> malloc(2)
    e = 0xBFBFEC7C -> malloc(strlen(ptr) * sizeof(char))
    a = 675299376
    b = 675303680
    c = 675299392
    d = 675303682
    e = 675307616
    a = supposedly the usupposedly the universe is infinitely large, the sheer size makes my head ache!
    b = susupposedly the universe is infinitely large, the sheer size makes my head ache!
    c = supposedly the universe is infinitely large, the sheer size makes my head ache!
    d = supposedly the universe is infinitely large, the sheer size makes my head ache!
    e = supposedly the universe is infinitely large, the sheer size makes my head ache!
    If you completely ommit mallocs, we get a core dump. I follow the need and usefullness of malloc, but:

    - Why don't we get a core dump when we allocate less than required storage and plunge data inside?
    - Why the strange output when printing a and b?
    - Why does c and d behave as if nothing is wrong?

    Above anything else, I would appreciate any feedback, and if you can, please be gentle - I am still getting to terms with many of C's more delicate parts :-)

    Finally, I'm selftaught in C with the dangers this inherits.

    Best regards,
    Storms
  2. #2
  3. No Profile Picture
    I haz teh codez!
    Devshed Frequenter (2500 - 2999 posts)

    Join Date
    Dec 2003
    Posts
    2,555
    Rep Power
    2338
    Start by turning up your compiler warnings and fixing them.

    Code:
    $ gcc -Wall -pedantic -o mallocs mallocs.c 
    mallocs.c: In function ‘main’:
    mallocs.c:13: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long unsigned int’
    mallocs.c:13: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long unsigned int’
    mallocs.c:15: warning: format ‘%X’ expects type ‘unsigned int’, but argument 2 has type ‘char **’
    mallocs.c:15: warning: format ‘%X’ expects type ‘unsigned int’, but argument 2 has type ‘char **’
    mallocs.c:16: warning: format ‘%X’ expects type ‘unsigned int’, but argument 2 has type ‘char **’
    mallocs.c:16: warning: format ‘%X’ expects type ‘unsigned int’, but argument 2 has type ‘char **’
    mallocs.c:17: warning: format ‘%X’ expects type ‘unsigned int’, but argument 2 has type ‘char **’
    mallocs.c:17: warning: format ‘%X’ expects type ‘unsigned int’, but argument 2 has type ‘char **’
    mallocs.c:18: warning: format ‘%X’ expects type ‘unsigned int’, but argument 2 has type ‘char **’
    mallocs.c:18: warning: format ‘%X’ expects type ‘unsigned int’, but argument 2 has type ‘char **’
    mallocs.c:19: warning: format ‘%X’ expects type ‘unsigned int’, but argument 2 has type ‘char **’
    mallocs.c:19: warning: format ‘%X’ expects type ‘unsigned int’, but argument 2 has type ‘char **’
    mallocs.c:21: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘char *’
    mallocs.c:21: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘char *’
    mallocs.c:22: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘char *’
    mallocs.c:22: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘char *’
    mallocs.c:23: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘char *’
    mallocs.c:23: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘char *’
    mallocs.c:24: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘char *’
    mallocs.c:24: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘char *’
    mallocs.c:25: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘char *’
    mallocs.c:25: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘char *’
    I ♥ ManiacDan & requinix

    This is a sig, and not necessarily a comment on the OP:
    Please don't be a help vampire!
  4. #3
  5. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2012
    Posts
    4
    Rep Power
    0
    Originally Posted by ptr2void
    Start by turning up your compiler warnings and fixing them.

    Code:
    $ gcc -Wall -pedantic -o mallocs mallocs.c 
    mallocs.c: In function ‘main’:
    mallocs.c:13: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long unsigned int’
    mallocs.c:13: warning: format ‘%d’ expects type ‘int’, but argument 2 has type ‘long unsigned int’
    mallocs.c:15: warning: format ‘%X’ expects type ‘unsigned int’, but argument 2 has type ‘char **’
    mallocs.c:15: warning: format ‘%X’ expects type ‘unsigned int’, but argument 2 has type ‘char **’
    mallocs.c:16: warning: format ‘%X’ expects type ‘unsigned int’, but argument 2 has type ‘char **’
    mallocs.c:16: warning: format ‘%X’ expects type ‘unsigned int’, but argument 2 has type ‘char **’
    mallocs.c:17: warning: format ‘%X’ expects type ‘unsigned int’, but argument 2 has type ‘char **’
    mallocs.c:17: warning: format ‘%X’ expects type ‘unsigned int’, but argument 2 has type ‘char **’
    mallocs.c:18: warning: format ‘%X’ expects type ‘unsigned int’, but argument 2 has type ‘char **’
    mallocs.c:18: warning: format ‘%X’ expects type ‘unsigned int’, but argument 2 has type ‘char **’
    mallocs.c:19: warning: format ‘%X’ expects type ‘unsigned int’, but argument 2 has type ‘char **’
    mallocs.c:19: warning: format ‘%X’ expects type ‘unsigned int’, but argument 2 has type ‘char **’
    mallocs.c:21: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘char *’
    mallocs.c:21: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘char *’
    mallocs.c:22: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘char *’
    mallocs.c:22: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘char *’
    mallocs.c:23: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘char *’
    mallocs.c:23: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘char *’
    mallocs.c:24: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘char *’
    mallocs.c:24: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘char *’
    mallocs.c:25: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘char *’
    mallocs.c:25: warning: format ‘%i’ expects type ‘int’, but argument 2 has type ‘char *’
    Point taken - and handled. This is however not related to the malloc stuff.
  6. #4
  7. Contributing User
    Devshed Demi-God (4500 - 4999 posts)

    Join Date
    Aug 2011
    Posts
    4,995
    Rep Power
    481
    "- Why don't we get a core dump when we allocate less than required storage and plunge data inside?"

    Investigate the memory layout of a c program. There could be many valid but sense-less addresses in the heap.
    [code]Code tags[/code] are essential for python code and Makefiles!
  8. #5
  9. Contributed User
    Devshed Specialist (4000 - 4499 posts)

    Join Date
    Jun 2005
    Posts
    4,417
    Rep Power
    1871
    > Makes good sense. There seems to be a debate as to whether the (myStruct *) explicit cast is nice C or bad C.
    Not really - those that know C well enough know it to be largely a bad thing.

    It has no positive benefits, and some very bad negative effects.
    The most serious is that with a cast, you DON'T get a warning if you fail to include stdlib.h. This leaves malloc without a prototype, and implicitly declares int malloc();
    Yes, malloc now returns an int (apparently). On machines with different sized pointers and ints (actually pretty common on 64-bit machines), this trashes pointers in unusual ways (but the cast masks all this).

    If you write it as
    Code:
    myStructPtr = malloc(sizeof(*myStructPtr));
    Then a whole host of maintenance problems go away.

    > The e pointer is malloc'd as I've learned to do.
    And even that is wrong.
    You should have allocated strlen(ptr)+1 bytes, because you need to allow room for the \0 at the end of the string.

    > - Why don't we get a core dump when we allocate less than required storage and plunge data inside?
    > - Why the strange output when printing a and b?
    > - Why does c and d behave as if nothing is wrong?
    All of these can be summarised as pure dumb luck.
    If you screw up, there are no guaranteed diagnostics. Anything can happen, including (apparently) giving you the right answer.

    For example, your failure to allocate strlen(ptr)+1 would be quite likely to go unnoticed for some length of time before it was caught.

    Which is why serious s/w development uses tools like valgrind to help locate memory issues which don't show up through regular testing.

    Your code would almost certainly crash if you tried further operations such as more malloc calls, or calling free after all those memory corrupting strcpy calls.

    Comments on this post

    • sepp2k1 agrees : Nice, comprehensive answer.
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper
  10. #6
  11. No Profile Picture
    Registered User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Sep 2012
    Posts
    4
    Rep Power
    0
    Thank you all for your replies.

    One of the best ways to learn with self studies are to have things blow up in your face. It's much harder to learn which you do well (or bad!) when they SEEM to function as you want them to.

    I still make a gazillion errors and following corrections or reading man-pages or googling while developing or peaking into the FreeBSD source to try to decipher how some property was obtained. However, in this specific case with malloc, the malloc source is pretty daunting for inexperienced C programmers.

    One of the things I have to improve a lot is to use the compiler (gcc in my case) more aggressively towards my code.

    I have tried lint, but it reports things anywhere, even in the C header files, so I'm not really sure what to make of it. I'm installing valgrind as we speak to, well, just play around and see where it takes me.

    I have so far used the constructive feedbacks to go over some of my other code to improve some of the areas, specifically typecasting malloc.

    Thanks so far to you all for shining a little light on my path ;)

IMN logo majestic logo threadwatch logo seochat tools logo