17 ms·
No, not at all. It doesn't run the program, the program isn't correct, it just compiles and links. Symbols don't know their types (... with some caveats about
by dllthomas 10y ago
No, not at all. It doesn't run the program, the program isn't correct, it just compiles and links. Symbols don't know their types (... with some caveats about name mangling in some languages).
- inlined 10y agoIn C, a function with no parameters is variadic. You need to add "void" to preclude parameters. This is one of the few breaking changes in C++ where no parameters means no parameters.
- dllthomas 10y agoTrue, but I'm not seeing the relevance. Just an interesting aside?
- int_19h 10y agoIt's legal to declare an external function symbol without specifying the parameters, so long as you actually match the types of real parameters (after all the standard conversions for functions with such prototypes are taken into account, like char -> int; and excluding some corner cases, like varargs) when you call it. If you don't actually call it, it's not U.B. However, the snippet above is still broken in that respect, because it doesn't match the return type of memcpy - and that is U.B.
- dllthomas 10y ago> It's legal to declare an external function symbol without specifying the parameters, so long as you actually match the types of real parameters Yes. And the call here does not match the types of the real parameters, even before we consider the return type.
- int_19h 10y agoRight, but (again, ignoring the return type) the call doesn't actually get executed, and U.B. only happens if it does. Though I guess they could have wrapped it in if(0){...} to make this completely unambiguous.
- dllthomas 10y agoIs your claim "there is no undefined behavior because the program is not run"? While that's true (there's no behavior, much less undefined behavior), in that case I don't see why the return type deserves calling out special. This program exhibits undefined behavior iff executed, and that would be true even if the return type were void * . > I guess they could have wrapped it in if(0){...} to make this completely unambiguous. Depending on optimizations, that may mean the executable does not depend on the symbol we're trying to test the presence of. Indeed, on my local gcc that's the case, even with -O0. $ cat test.c void *memcpy(); int main() { if(TEST) { (void)memcpy(); } } $ gcc -DTEST=0 test.c $ objdump -T a.out a.out: file format elf64-x86-64 DYNAMIC SYMBOL TABLE: 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 __libc_start_main 0000000000000000 w D *UND* 0000000000000000 __gmon_start__ $ gcc -DTEST=1 test.c $ objdump -T a.out a.out: file format elf64-x86-64 DYNAMIC SYMBOL TABLE: 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 __libc_start_main 0000000000000000 w D *UND* 0000000000000000 __gmon_start__ 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.14 memcpy $ gcc -O0 -DTEST=0 test.c $ objdump -T a.out a.out: file format elf64-x86-64 DYNAMIC SYMBOL TABLE: 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 __libc_start_main 0000000000000000 w D *UND* 0000000000000000 __gmon_start__ c.f.: $ cat test.c void *blah(); int main() { if(TEST) { (void)blah(); } } $ gcc -DTEST=1 test.c /tmp/cc2Vk5mE.o: In function `main': test.c:(.text+0xa): undefined reference to `blah' collect2: error: ld returned 1 exit status $ gcc -DTEST=0 test.c $ objdump -T a.out a.out: file format elf64-x86-64 DYNAMIC SYMBOL TABLE: 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 __libc_start_main 0000000000000000 w D *UND* 0000000000000000 __gmon_start__ $ gcc -O0 -DTEST=0 test.c $ objdump -T a.out a.out: file format elf64-x86-64 DYNAMIC SYMBOL TABLE: 0000000000000000 DF *UND* 0000000000000000 GLIBC_2.2.5 __libc_start_main 0000000000000000 w D *UND* 0000000000000000 __gmon_start__