Reputation: 3767
here is a snippet of my program
#include <stdio.h>
#include <string.h>
void something_wrong_really(char *str)
{
char *savedptr = NULL;
char *delim = " ";
for ( char *p = str ; ; p = NULL) {
char *token = strtok_r(p, delim, &savedptr);
if (token == NULL)
break;
printf(" %s\n", token);
}
}
int main(void) {
char str[] = "Okay so lets split this and see how it works";
something_wrong_really(str);
return 0;
}
based on the strtok_r
manual
strtok_r(): _POSIX_C_SOURCE || / Glibc versions <= 2.19: / _BSD_SOURCE || _SVID_SOURCE
so if I compile my program as
cc t.c -std=c99
I end up getting warning
t.c: In function 'something_wrong_really':
t.c:10:3: warning: implicit declaration of function 'strtok_r' [-Wimplicit-function-declaration]
char *token = strtok_r(p, delim, &savedptr);
^
t.c:10:17: warning: initialization makes pointer from integer without a cast [enabled by default]
char *token = strtok_r(p, delim, &savedptr);
^
whats worse on execution it segfaults
./a.out
Segmentation fault
corresponding trace
Program received signal SIGSEGV, Segmentation fault.
0x00007ffff7a5af19 in vfprintf () from /lib64/libc.so.6
Missing separate debuginfos, use: debuginfo-install glibc-2.17-222.el7.x86_64
(gdb) bt
#0 0x00007ffff7a5af19 in vfprintf () from /lib64/libc.so.6
#1 0x00007ffff7a61339 in printf () from /lib64/libc.so.6
#2 0x00000000004005e2 in something_wrong_really (str=0x7fffffffe0a0 "Okay") at t.c:13
#3 0x0000000000400653 in main () at t.c:19
(gdb)
on the other hand thing seem to work perfectly fine when enabled one of these flags
_SVID_SOURCE || _BSD_SOURCE || _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE
corresponding output
# cc t.c -std=c99 -D_BSD_SOURCE
#
#
# ./a.out
Okay
so
lets
split
this
and
see
how
it
works
#
any hints on why this behavior ?
so it seems the snippet in strtok_r manual
Feature Test Macro Requirements for glibc (see feature_test_macros(7)):
strtok_r(): _POSIX_C_SOURCE || /* Glibc versions <= 2.19: */ _BSD_SOURCE || _SVID_SOURCE
is explained (very loosely) here feature_test_macros
The || means that in order to obtain the declaration of acct(2) from , either of the following macro definitions must be made before including any header files:
#define _BSD_SOURCE #define _XOPEN_SOURCE /* or any value < 500 */ Alternatively, equivalent definitions can be included in the compila‐ tion command: cc -D_BSD_SOURCE cc -D_XOPEN_SOURCE # Or any value < 500
so as @Some programmer dude pointed out inclusion of those MACRO definitions is a must else it leads to UB which eventually is what happened here.
Upvotes: 1
Views: 300
Reputation: 409176
If you do not use the correct enabling macro (_POSIX_C_SOURCE
according to the manual page) then the function will not be automatically declared. That means the compiler must deduce the argument types, and more importantly the return type will automatically be int
(as noted in the second warning message).
If the argument types or the return type are wrong, then that call will lead to undefined behavior, and very likely crashes.
By adding the correct macros, the function will be properly declared in the header file, and the correct types for arguments and returned value will be used.
The problem here is probably the mismatched return type. On a 64-bit system pointers (like e.g. char *
) are 64 bits wide, while int
is usually only 32 bits wide. This mismatch in sizes will cause many pointers to be wrong, and attempting to use them is a great source of segmentation faults.
Upvotes: 3