https://gcc.gnu.org/bugzilla/show_bug.cgi?id=107932
Bug ID: 107932 Summary: weak constant char array not used correctly Product: gcc Version: 9.4.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: bseifert at gmx dot at Target Milestone: --- given the following files: def.hpp ----------- #include <string> struct A { static const char* C1; static const char C2[]; static const char C3[]; static std::string get_C1(); static std::string get_C2(); static std::string get_C3(); }; ----------- weak.cpp ----------- #include "def.hpp" std::string A::get_C1() { return C1; } std::string A::get_C2() { return C2; } std::string A::get_C3() { return C3; } __attribute__((weak)) const char* A::C1 = "w"; __attribute__((weak)) const char A::C2[] = "w"; __attribute__((weak)) const char A::C3[] = ""; ----------- main.cpp ----------- #include <stdio.h> #include "def.hpp" const char* A::C1 = "S"; const char A::C2[] = "S"; const char A::C3[] = "S"; int main() { printf("'%s'\n", A::get_C1().data()); printf("'%s'\n", A::get_C2().data()); printf("'%s'\n", A::get_C3().data()); } ----------- the constant char pointer C1 in A is defined weak in weak.cpp (pointing to the char array "w"). constant char array C2 in A is defined weak in weak.cpp (initialized to "w"). constant char array C3 in A is defined weak in weak.cpp (initialized to ""). in main.cpp all these constants are defined strong and initilaized to / pointing to "S". The getter methodes get_C1, get_C2 and get_C3 make std::string out of the constants and return the string respectively. it is expected that in all three cases the string "S" is returned. test case: g++ -o test.exe -O2 main.cpp weak.cpp ./test.exe 'S' 'S' '' it seems that the compilation of get_C3 is not done properly (wrongly optimized) because the compiler seems to wrongly assume a fixed length of 0 even though the constant is attributed weak! here is the assembly of the methods: weak.lss ----------- 0000000000000000 <A::get_C1[abi:cxx11]()>: 0: f3 0f 1e fa endbr64 4: 41 56 push %r14 6: 41 55 push %r13 8: 41 54 push %r12 a: 55 push %rbp b: 48 8d 6f 10 lea 0x10(%rdi),%rbp f: 48 83 ec 18 sub $0x18,%rsp 13: 4c 8b 35 00 00 00 00 mov 0x0(%rip),%r14 # 1a <A::get_C1[abi:cxx11]()+0x1a> 1a: 64 48 8b 04 25 28 00 mov %fs:0x28,%rax 21: 00 00 23: 48 89 44 24 08 mov %rax,0x8(%rsp) 28: 31 c0 xor %eax,%eax 2a: 48 89 2f mov %rbp,(%rdi) 2d: 4d 85 f6 test %r14,%r14 30: 0f 84 a2 00 00 00 je d8 <A::get_C1[abi:cxx11]()+0xd8> 36: 49 89 fc mov %rdi,%r12 39: 4c 89 f7 mov %r14,%rdi 3c: e8 00 00 00 00 callq 41 <A::get_C1[abi:cxx11]()+0x41> 41: 48 89 04 24 mov %rax,(%rsp) 45: 49 89 c5 mov %rax,%r13 48: 48 83 f8 0f cmp $0xf,%rax 4c: 77 52 ja a0 <A::get_C1[abi:cxx11]()+0xa0> 4e: 48 83 f8 01 cmp $0x1,%rax 52: 75 3c jne 90 <A::get_C1[abi:cxx11]()+0x90> 54: 41 0f b6 16 movzbl (%r14),%edx 58: 41 88 54 24 10 mov %dl,0x10(%r12) 5d: 49 89 44 24 08 mov %rax,0x8(%r12) 62: c6 44 05 00 00 movb $0x0,0x0(%rbp,%rax,1) 67: 48 8b 44 24 08 mov 0x8(%rsp),%rax 6c: 64 48 33 04 25 28 00 xor %fs:0x28,%rax 73: 00 00 75: 75 6d jne e4 <A::get_C1[abi:cxx11]()+0xe4> 77: 48 83 c4 18 add $0x18,%rsp 7b: 4c 89 e0 mov %r12,%rax 7e: 5d pop %rbp 7f: 41 5c pop %r12 81: 41 5d pop %r13 83: 41 5e pop %r14 85: c3 retq 86: 66 2e 0f 1f 84 00 00 nopw %cs:0x0(%rax,%rax,1) 8d: 00 00 00 90: 48 85 c0 test %rax,%rax 93: 74 c8 je 5d <A::get_C1[abi:cxx11]()+0x5d> 95: eb 26 jmp bd <A::get_C1[abi:cxx11]()+0xbd> 97: 66 0f 1f 84 00 00 00 nopw 0x0(%rax,%rax,1) 9e: 00 00 a0: 48 89 e6 mov %rsp,%rsi a3: 31 d2 xor %edx,%edx a5: 4c 89 e7 mov %r12,%rdi a8: e8 00 00 00 00 callq ad <A::get_C1[abi:cxx11]()+0xad> ad: 49 89 04 24 mov %rax,(%r12) b1: 48 89 c5 mov %rax,%rbp b4: 48 8b 04 24 mov (%rsp),%rax b8: 49 89 44 24 10 mov %rax,0x10(%r12) bd: 48 89 ef mov %rbp,%rdi c0: 4c 89 ea mov %r13,%rdx c3: 4c 89 f6 mov %r14,%rsi c6: e8 00 00 00 00 callq cb <A::get_C1[abi:cxx11]()+0xcb> cb: 48 8b 04 24 mov (%rsp),%rax cf: 49 8b 2c 24 mov (%r12),%rbp d3: eb 88 jmp 5d <A::get_C1[abi:cxx11]()+0x5d> d5: 0f 1f 00 nopl (%rax) d8: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # df <A::get_C1[abi:cxx11]()+0xdf> df: e8 00 00 00 00 callq e4 <A::get_C1[abi:cxx11]()+0xe4> e4: e8 00 00 00 00 callq e9 <A::get_C1[abi:cxx11]()+0xe9> e9: 90 nop ea: 66 0f 1f 44 00 00 nopw 0x0(%rax,%rax,1) 00000000000000f0 <A::get_C2[abi:cxx11]()>: f0: f3 0f 1e fa endbr64 f4: 48 8d 47 10 lea 0x10(%rdi),%rax f8: 41 54 push %r12 fa: 49 89 fc mov %rdi,%r12 fd: 48 89 07 mov %rax,(%rdi) 100: 48 8d 3d 00 00 00 00 lea 0x0(%rip),%rdi # 107 <A::get_C2[abi:cxx11]()+0x17> 107: e8 00 00 00 00 callq 10c <A::get_C2[abi:cxx11]()+0x1c> 10c: 48 83 f8 01 cmp $0x1,%rax 110: 75 0c jne 11e <A::get_C2[abi:cxx11]()+0x2e> 112: 0f b6 15 00 00 00 00 movzbl 0x0(%rip),%edx # 119 <A::get_C2[abi:cxx11]()+0x29> 119: 41 88 54 24 10 mov %dl,0x10(%r12) 11e: 49 89 44 24 08 mov %rax,0x8(%r12) 123: 41 c6 44 04 10 00 movb $0x0,0x10(%r12,%rax,1) 129: 4c 89 e0 mov %r12,%rax 12c: 41 5c pop %r12 12e: c3 retq 12f: 90 nop 0000000000000130 <A::get_C3[abi:cxx11]()>: 130: f3 0f 1e fa endbr64 134: 48 8d 57 10 lea 0x10(%rdi),%rdx 138: 48 c7 47 08 00 00 00 movq $0x0,0x8(%rdi) 13f: 00 140: 48 89 f8 mov %rdi,%rax 143: 48 89 17 mov %rdx,(%rdi) 146: c6 47 10 00 movb $0x0,0x10(%rdi) 14a: c3 retq ----------- Though the pointer should be used in all three cases to call the constructor of std::string, the three constants are treated completely different. I cannot say what the exact difference between get_C1 and get_C2 is in the implementation, but definitely get_C3 is not correct. it does not matter if the weak definitions in weak.cpp are before or after the definition of the methods (in contrast to bug 107907) even casting the constants, does not help: ----------- std::string A::get_C1() { return (const char*) C1; } std::string A::get_C2() { return (const char*) C2; } std::string A::get_C3() { return (const char*) C3; } -----------