Thread: Can someone remind me how to tell gcc not to 0 initialise everything in debug mode

  1. #31
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    So many bugs.

    Oh wait, you haven't run valgrind have you.

    Code:
    void* grow_buffer( struct buffer *B, uint total )
    {
        void *array;
        if ( B->total >= total )
            return B->array;
        array = realloc( B->array, B->Tsize * total );
        if ( !array )
            return NULL;
        B->array = array;
        B->total = total;
        return array;
    }
    Which is broken, but hey it's C89 compatible, so it's all good.

    Why is it broken?
    Because >=
    Or more specifically, the equals case.

    But as anyone who knows C knows, given an array of N elements, accessing a[N] is out of bounds.

    Compared to the one you derided for scope issues, which is at least correct.
    Code:
    void* grow_buffer( struct buffer *B, uint total )
    {
        if ( B->total < total )
        {
            void *array = realloc( B->array, B->Tsize * total );
            if ( !array )
                return NULL;
            B->array = array;
            B->total = total;
        }
        return B->array;
    }
    > array = more_members( &B, count + strlen(tmp_text) );
    Yet more off by one.
    You forgot to count the \0

    No wonder you have so many problems........
    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.

  2. #32
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by Salem View Post
    So many bugs.

    Oh wait, you haven't run valgrind have you.

    Code:
    void* grow_buffer( struct buffer *B, uint total )
    {
        void *array;
        if ( B->total >= total )
            return B->array;
        array = realloc( B->array, B->Tsize * total );
        if ( !array )
            return NULL;
        B->array = array;
        B->total = total;
        return array;
    }
    Which is broken, but hey it's C89 compatible, so it's all good.

    Why is it broken?
    Because >=
    Or more specifically, the equals case.

    But as anyone who knows C knows, given an array of N elements, accessing a[N] is out of bounds.

    Compared to the one you derided for scope issues, which is at least correct.
    Code:
    void* grow_buffer( struct buffer *B, uint total )
    {
        if ( B->total < total )
        {
            void *array = realloc( B->array, B->Tsize * total );
            if ( !array )
                return NULL;
            B->array = array;
            B->total = total;
        }
        return B->array;
    }
    > array = more_members( &B, count + strlen(tmp_text) );
    Yet more off by one.
    You forgot to count the \0

    No wonder you have so many problems........
    First, you realise that's code I wrote off the top of my head right, the actual struct I use has a boolean to indicate it's a string in which is added to the count in a separate variable which is what is actually compared against the total, the count in that case is always matching what strlen would produce which is far less confusing than constantly trying to detect if the count is 1. greater than 0 & 2. in which case minus 1 from it, easier to just use the count as is and let the count management functions ensure the count is less than the total by at least 1.

    Second in what way is it broken to return the current allocation when the total for that allocation is greater than or equal what is requested? You'll still have the elements you requested, even if you pass 0 as the total.

  3. #33
    Registered User
    Join Date
    Sep 2020
    Posts
    425
    Quote Originally Posted by awsdert View Post
    First, you realise that's code I wrote off the top of my head right
    How were they to know? Wasn't a "foo" or "bar" in sight...

  4. #34
    Registered User
    Join Date
    Sep 2020
    Posts
    425
    Since all your allocation/reallocation/frees happens in one place why don't you:

    - Always allocate 4 more bytes.

    - Fill them with known magic values (e.g. 0xDE, 0xAD, 0xBE, 0xEF)

    - Have something that verifies that this value hasn't been trashed when you reallocate() or free(), or whenever you need to.

    - Zero out any data that is freed.

    You will quickly PROVE if you are (or are not) writing past the end of the allocated space, and will be a useful feature in the future.

    This technique has helped me track down significant bugs before...

  5. #35
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    > First, you realise that's code I wrote off the top of my head right,
    Or pulled out of your arse.

    Same goes for all of this thread.
    The whole thing is an XY Problem

    You have a problem, you imagine a 'fix' (some BS about initialisation), but is the real problem that you can't count?

    If your next reply isn't REAL runnable code showing an actual problem, expect this thread to be closed.
    2 days and nearly 40 replies, and nobody still has a f-ing clue about what dope you're smoking.

    You wittering on about how C89 is so marvellous and other side tracks isn't relevant or interesting.
    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.

  6. #36
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by Salem View Post
    > First, you realise that's code I wrote off the top of my head right,
    Or pulled out of your arse.

    Same goes for all of this thread.
    The whole thing is an XY Problem

    You have a problem, you imagine a 'fix' (some BS about initialisation), but is the real problem that you can't count?

    If your next reply isn't REAL runnable code showing an actual problem, expect this thread to be closed.
    2 days and nearly 40 replies, and nobody still has a f-ing clue about what dope you're smoking.

    You wittering on about how C89 is so marvellous and other side tracks isn't relevant or interesting.
    When did I say C89 was marvellous? I said I prefer to stay compatible with it as much as possible, 2 VERY different things, I actually prefer C99 mainly for long long but also for the inline keyword, and no I'm not looking for help with X, it is the impetus yes, but not the reason for this thread, I'm not a fan of the 0xDEADBEEF idea that was suggested as that requires extra variables to keep track of it's position, that can confuse external developers that access the internals of the object, it isn't the purpose of the buffer to make sure nothing was written beyond what should've been, that is out of scope, I can perhaps get behind a wrapper object whose sole purpose is that scope but not corrupting the purpose of the buffer object. The alternative is simply relying only on the element function to retrieve the pointer (which will return NULL if not in bounds). Anyways all the functions that use the array as a whole instead of just individual elements always make sure compare their index against the count which is not directly grown by them, they'll happily set it to 0 but any growth goes through the dedicated functions so I couldn't be more certain it's not the dynamic filling at fault.

  7. #37
    Registered User awsdert's Avatar
    Join Date
    Jan 2015
    Posts
    1,733
    Quote Originally Posted by hamster_nz View Post
    How were they to know? Wasn't a "foo" or "bar" in sight...
    That would obfuscate the purpose of the function, no point giving a example if the purpose is unknown, to refer to another post, the purpose could be X but instead doing Y, if you don't even know about X then you'll only address Y, though that expectation appears to have fallen flat here as the ONLY thing I was expecting in this thread was identifying how to make debug behaviour the same as release behaviour (albeit slower), all this other stuff is off topic and I'd really like us to get back on topic.

  8. #38
    Registered User
    Join Date
    Sep 2020
    Posts
    425
    Quote Originally Posted by awsdert View Post
    The ONLY thing I was expecting in this thread was identifying how to make debug behaviour the same as release behaviour (albeit slower), all this other stuff is off topic and I'd really like us to get back on topic.
    What is the difference between your release and debug builds? different #defines? different compiler options? Currently we have no idea!

    Assuming it is only compiler options, then:

    - you may have (most likely unintentional) invoked undefined behaviour somewhere in you code, allowing the compiler to make optimizations you are not expecting.

    - Your code may be trashing memory, and the effects of this are different because of the optimizations.

    Take for example this code:

    Code:
    #include <stdio.h>
    
    
    void f(int *a, int *c) {
      printf("Difference is %zi\n",c-a);
    }
    
    
    int main(void)
    {
       int b[10];
       int sum = 0;
       // Do something to use those variables
       for(int i = 0; i < 10; i++)
         b[i] = i;
    
    
       for(int i = 0; i < 10; i++)
         sum += b[i];
    
    
       printf("sum is %i\n",sum);
    
    
       f(b,&sum);
       return 0;
    }
    It compiles cleanly, but gives different output depending of optimizations are turned on or not:

    Code:
    hamster@hamster-acer5:~/help/help4$ gcc -o main main.c -Wall -pedantic -Wextra && ./main
    sum is 45
    Difference is -3
    hamster@hamster-acer5:~/help/help4$ gcc -o main main.c -Wall -pedantic -Wextra -O3 && ./main
    sum is 45
    Difference is -1

    I'm not saying your code has the same problem as that bit of code - I've not seen your code

    I'm not saying that the difference between your builds is just the "-O3" flag.

    I'm just proving it is quite easy to write code that compiles cleanly, and on the surface has no UB, but is still sensitive to compiler options.

    In these cases it is 99.99% of the time the fault of the code, not the compiler. You need to examine your code with a very critical eye, and possibly even instrument your code to find out where, so you can find out why. Using obscure compiler options will not be of much help.
    Last edited by hamster_nz; 04-04-2022 at 02:27 PM.

  9. #39
    Registered User
    Join Date
    Sep 2020
    Posts
    425
    Quote Originally Posted by awsdert View Post
    I'm not a fan of the 0xDEADBEEF idea that was suggested as that requires extra variables to keep track of it's position...
    If anybody is here looking for the "xDEADBEEF" idea, here it is:

    Here's some bad code:

    Code:
    int main(void)
    {
       char *a;
       a = my_malloc(17);
       memset(a,0,17);
       my_free(a);
    
       a = my_malloc(17);
       memset(a,0,18);
       my_free(a);
       return 0;
    }
    Note that nobody hast to keep track of extra variables. You just have to use my_malloc() and my_free() rather than malloc() and free().

    Here's what happens when you run it:

    Code:
    my_malloc()
    my_free()
    my_malloc()
    my_free()
    Corruption detected - block trailer is trashed - get out the debugger!
    That "Corruption detected" message is generated when my_free() is called.

    And here is the tiny implementation I hacked up, less than a printed page of code
    Code:
    #include <stdio.h>
    #include <malloc.h>
    #include <memory.h>
    #include <stdlib.h>
    
    #define HEADER_MAGIC 0xF00DBEEFU
    unsigned char trailer_magic[4] = {0xDE, 0xAD, 0xBE, 0xEF};
    
    struct malloc_header {
       size_t magic;
       size_t size;
    };
    
    static void *my_malloc(size_t size) {
       void *raw;
       struct malloc_header *hdr;
       unsigned char *data;
    
       printf("my_malloc()\n");
       raw = malloc(size+sizeof(struct malloc_header)+sizeof(trailer_magic));
       if(raw == NULL) return NULL;
    
       hdr = raw;
       data = raw;
       data += sizeof(struct malloc_header);
       hdr->magic = HEADER_MAGIC;
       hdr->size = size;
       memcpy(data+size,trailer_magic,sizeof(trailer_magic));
       return data;
    }
    
    
    void my_free(void *ptr) {
       printf("my_free()\n");
       struct malloc_header *hdr = ptr;
       unsigned char *data = ptr;
       hdr--;
    
       if(hdr->magic != HEADER_MAGIC) {
          fprintf(stderr, "That's weird - not allocated with my_magic or trashed\n");
          exit(0);
       }
       if(memcmp(trailer_magic, data+hdr->size, sizeof(trailer_magic)) != 0) {
          fprintf(stderr, "Corruption detected - block trailer is trashed - get out the debugger!\n");
          exit(0);
       }
    
       // Clear out the magic values, allowing us to detect double frees
       memset(data+hdr->size, 0, sizeof(trailer_magic));
       hdr->magic = 0;
       free(hdr);
    }
    Implementing my_realloc() and my_calloc() is left to the user.

    You could also add a "my_checkptr()" so you could validate that your heap hasn't been trashed.

    e.g.
    Code:
       strcat(ptr, "foo and bar");
       my_checkptr(ptr); // Doublecheck that the buffer hasn't been exceeded
    And of course with the correct #defines all of this could be replaced by plain old malloc() and free() in your "release" build.
    Last edited by hamster_nz; 04-04-2022 at 04:14 PM.

  10. #40
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,659
    No code.
    Closed.
    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.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 1
    Last Post: 04-24-2010, 01:35 PM
  2. Using the Debug mode ((F10) V.S 2005
    By csonx_p in forum Windows Programming
    Replies: 21
    Last Post: 06-17-2008, 05:06 PM
  3. Debug Mode
    By Coding in forum C# Programming
    Replies: 5
    Last Post: 02-14-2008, 03:00 PM
  4. Replies: 4
    Last Post: 09-16-2006, 07:11 PM
  5. Debug Mode Vs. Release Mode
    By incognito in forum Tech Board
    Replies: 5
    Last Post: 12-18-2003, 04:06 PM

Tags for this Thread