Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are __func__ and __FUNCTION__ pointers persistent?

Tags:

c

gcc

gnu

For gcc projects, are the pointers returned by __FUNCTION__, __FILE__ and __func__ guaranteed to point to persistent memory? (That is, can I safely deference the pointers in the scope of another function?) I know that __func__ is supposed to act like a const char __func__ = "filename" at the beginning of the function, which implies that "filename" points to something in the data segment of the program, and that the pointer should therefore be valid outside of the function. The others are strings, which again, should create entries in the data section. That being said, I don't trust it, and I'm wondering if someone here can confirm whether the assumption is correct.

For example:

struct debugLog_t {
      const char * func;
      const char * file;
      const char * function;
      uint32_t     line;
      int          val;
} log;

struct debugLog_t someLog = {};

someFunc() {
      // create debug log:
      if (x) {
           //uh oh... 
           someLog.func = __func__;
           someLog.function = __FUNCTION__;
           someLog.file = __FILE__;
           someLog.line = line;
           someLog.val = val;
      }
}

void dumpSomeLog() {
      printf("%s(%s) -- %s.%d: error val is x\n", 
             someLog.function, someLog.func, someLog.file, someLog.line,
             someLog.val);
}

I want to do this to reduce memory/processing time of recording debug logs.

like image 358
HardcoreHenry Avatar asked Mar 19 '26 16:03

HardcoreHenry


1 Answers

I won't call that persistent memory (read wikipage on persistence) but read only memory (or section) in the code segment.

And yes, __func__, __FUNCTION__, __FILE__ go there (as static const char[] arrays); like literal strings.

Notice that two occurrences of a literal string like "ab" may or not be compiled into the same addresses (likewise, "bc" can or not be equal to pointer "abc"+1). Likewise for two occurrences of __FILE__; however, within the same function, all occurrences of __func__ should have the same address.

With GCC (at least at -O1 optimization) literal constant strings of the same content share the same location. I would even believe that in function foo the __func__ and "foo" might share the same address (but with GCC they don't, even at -O2). You could check by compiling with gcc -fverbose-asm -S -O1 and look at the generated *.s assembler file.

For example:

 const char*f(int x) { 
   if (x==0) return "f";
   if (x>0) return  __func__;
   return __FUNCTION__;
 }

gets compiled with gcc -O -fverbose-asm -S (using GCC 7 on Linux/Debian/Sid/x86-64) as

    .section    .rodata.str1.1,"aMS",@progbits,1
 .LC0:
    .string "f"
    .text
    .globl  f
    .type   f, @function
 f:
 .LFB0:
    .cfi_startproc
 # f.c:2:   if (x==0) return "f";
    leaq    .LC0(%rip), %rax    #, <retval>
    testl   %edi, %edi  # x
    je  .L1 #,
 # f.c:3:   if (x>0) return  __func__;
    testl   %edi, %edi  # x
 # f.c:4:   return __FUNCTION__;
    leaq    __func__.1795(%rip), %rax   #, tmp94
    leaq    __FUNCTION__.1796(%rip), %rdx   #, tmp95
    cmovle  %rdx, %rax  # tmp94,, tmp95, <retval>
 .L1:
 # f.c:5: }
    rep ret
    .cfi_endproc
 .LFE0:
    .size   f, .-f
    .section    .rodata
    .type   __FUNCTION__.1796, @object
    .size   __FUNCTION__.1796, 2
 __FUNCTION__.1796:
    .string "f"
    .type   __func__.1795, @object
    .size   __func__.1795, 2
 __func__.1795:
    .string "f"
    .ident  "GCC: (Debian 7.2.0-8) 7.2.0"

Even with -Os or -O3 I'm getting three different locations in the code segment.

However Clang 5 with -O3 (or even -O1) merge all three "f", __FUNCTION__ and __func__ by putting them at the same location (and optimize the test by removing it):

    .type   f,@function
f:                                      # @f
    .cfi_startproc
# BB#0:
    movl    $.L.str, %eax
    retq
.Lfunc_end0:
    .size   f, .Lfunc_end0-f
    .cfi_endproc
                                        # -- End function
    .type   .L.str,@object          # @.str
    .section    .rodata.str1.1,"aMS",@progbits,1
.L.str:
    .asciz  "f"
    .size   .L.str, 2

So the pointers you care about are pointers to static const char[] in the code segment but you should not always expect that __func__ has the same address than __FUNCTION__ (even if that could be).

like image 52
Basile Starynkevitch Avatar answered Mar 22 '26 10:03

Basile Starynkevitch