Closed varqox closed 4 years ago
Thanks for the careful analysis! I did not notice this problem as it does not show up on macOS.
I am not sure about the implications of -D_POSIX_C_SOURCE=200809L
. (Does it fix the problem on all platforms? Could it pose problems on some platforms?)
A simple fix could be to use a hand-rolled implementation of strdup
, in the line of https://stackoverflow.com/questions/252782/strdup-what-does-it-do-in-c .
I changed the fix to define _POSIX_C_SOURCE
in the generated .l
file in a @top{...}
block rather than passing it to the C compiler in the Makefile.
Encountered on version v2.8.4 (did not check others).
How to reproduce
Create file
Instant.cf
:Compile:
Run:
Output:
Expected output:
What is going on?
I did some investigation and I think I know why this happens. First of all, it is printing that fails, because it tries to print
Ident
"a", but its value is invalid (for me it is 0x30 under GDB). This value comes fromstrdup()
. Now, duringmake
the compiler gave us some warnings, which look like this:From there we see that GCC cannot see
strdup()
declaration and makes an implicit one i.e. "int strdup();" instead of "char strdup();" (function arguments do not matter here, what is important is the return type). What happens during execution is that: the proper strdup() is called -- the one from libc. But C converts its return value to the one from declaration i.e. int, before using it. So instead of 64bit pointer we have now a 32bit integer made from that pointer and then we convert it back to the char pointer, but the upper 32 bits will remain zeroed, hence the invalid pointer from strdup().So why the compiler does not see the proper declaration of strdup()? If we take a look at
man 3 strdup
, we can see that it is conditionally enabled:and the C flags from the make file do not make it enabled.
How to fix it?
So the proper solution would be to make strdup() visible. How can it be done? There are several ways:
-D_GNU_SOURCE
or-D_BSD_SOURCE
or-D_POSIX_C_SOURCE=200809L
The last one is seems most viable IMO. That is because it is not as broad as
_GNU_SOURCE
, also fixes the last warning (from the ones above):and POSIX is a widely approved standard.