cmemorylexical-scope

Is block-scope buffer valid outside of the block in C


Can the following can be considered safe practice?

void some_func(void) {
    const char * foo;

    if (SOME_MACRO()) {
       char * foo_buf[20];
       snprintf(foo_buf,sizeof(foo_buf),"blah_%d",some_global);
       foo = foo_buf;
    } else {
       foo = "some constant string";
    }
    // do a bunch of other stuff here...
    printf("%s\n", foo);
}

This makes the assumption that the memory in foo_buf is still valid (and unchanged) outside of the block scope. I'm concerned if there are any situations where the compiler discards or overwrites block specific memory when the block has exited.

The reason I'd like the declaration in the block rather than in global scope is that on some platforms, SOME_MACRO() would resolve to a constant, in others, to an expression, so the code inside the if block can be optimized out in some cases.


Solution

  • It's UB.

    Lifting char * foo_buf[20]; up shouldn't give you worse code. All the function's locals are likely to be allocated at the top anyway and compilers are quite well capable of eliminating locals that get never used.

    Try compiling:

    #define UP 0
    #define CONST 1
    
    #include <stdio.h>
    
    #if CONST
       #define SOME_MACRO() 0
    #else
       int SOME_MACRO(void);
    #endif
    
    int some_global;
    
    
    void some_func(void) {
        const char * foo;
    
        #if UP
            char foo_buf[20]; // Fixed from char *foo_buf[20];
        #endif
    
        if (SOME_MACRO()) {
    
            #if !UP
                char foo_buf[20]; //fixed from char *foo_buf[20];
            #endif
    
           snprintf(foo_buf,sizeof(foo_buf),"blah_%d",some_global);
           foo = foo_buf;
        } else {
           foo = "some constant string";
        }
        // Do a bunch of other stuff here...
        printf("%s\n", foo);
    }
    

    with with CONST set to either 0 or 1 and then changing UP to between 0 and 1.

    With GCC, Clang, or Intel C++ Compiler, moving the declaration (by changing UP) doesn't make any difference, even at -O0: See this code at Compiler Explorer.