Reputation: 1531
I have the following code:
static char sessionid[SESSIONID_LEN+1] = { '\0' };
static void generate_sessionid() {
char set[] = "0123456789"
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int len;
memset(sessionid, 0, sizeof(char) * SESSIONID_LEN);
for (len = 0; len < SESSIONID_LEN; len++) {
size_t index = (double) rand()/RAND_MAX*(sizeof(set) - 1);
sessionid[len] = set[index];
}
}
char *get_sessionid() {
if (strlen(sessionid) == 0) generate_sessionid();
char * dup = strdup(sessionid);
return dup;
}
I call get_sessionid()
from a different thread (whose function is defined in a different file). When I break in line 2 of get_sessionid()
and examine the pointer address returned by strdup()
, this is the value:
0x7f7788c004f50
Now, when I return from this function and examine the returned value caught in the thread function, the return value is different:
0xfffffffffc004f50
And subsequently when I call strlen()
on this returned pointer value, I get a SIGSEGV
and the reason being Address 0xfffffffffc004f50 out of bounds
The two files are part of a big application that have around 30 threads running and many more memory allocations happening elsewhere. I also think memory has been leaked by other threads. But I want to make sure that something is not wrong in the above code.
I verified the above code separately and everything works fine, the return value is not corrupt, i.e, it works perfectly fine when isolated from the rest of the program. But I don't understand why the return value is getting changed when run in the context of the whole program.
Edit (attachments)
In the thread function I call as:
thread.c
#include <header.h>
login_sessionid = (char*)get_sessionid();
In the header: header.h
char * get_sessionid(void);
Compiler warnings:
warning: implicit declaration of function ‘get_sessionid’ [-Wimplicit-function-declaration]
warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
Both the above warnings are at the line shown (above) of the file thread.c
Upvotes: 1
Views: 1245
Reputation: 46960
In addition to what @Jonathan Leffler said, if more than one thread can call this routine, there is a race condition allowing different threads to get different id's even though they are separate copies.
One example of what can occur:
In general, static storage (with no mutex) and multiple threads do not mix. This is a classic problem with the singleton pattern in multi-threaded environments.
Upvotes: 3
Reputation: 753695
The chances are rather high that the code in the other file doesn't realize that get_sessionid()
returns a pointer so it assumes it returns an integer and then sign-extends that to create a pointer.
Your compiler is probably warning about undeclared functions; if it isn't, turn up the warning levels until it does. It should also be warning about converting an integer to a pointer of a different size.
Pay attention to the warnings your compiler gives. Remember, it knows more about C than you do.
Also make sure the compiler gives you as many warnings as possible. If you use gcc
, you should be compiling cleanly with gcc -Wall -Wextra -Werror -Wmissing-prototypes -Wold-style-definition -Wold-style-declaration
; that's my current benchmark (with -std=c11
or -std=c99
). If your version doesn't support the old style warnings, you can simply leave them out.
Upvotes: 4