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.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With