I've never needed to use strdup(stringp)
with strsep(&stringp_copy, token)
together until recently and I think it was causing a memory leak.
(strdup()
has always free
'd just fine before.)
I fixed the leak, and I think I understand how, but I just can't figure out why I needed to.
Original code (summarized):
const char *message = "From: username\nMessage: basic message\n";
char *message_copy, *line, *field_name;
int colon_position;
message_copy = strdup(message);
while(line = strsep(&message_copy, "\n")) {
printf(line);
char *colon = strchr(line, ':');
if (colon != NULL) {
colon_position = colon - line;
strncpy(field_name, line, colon_position);
printf("%s\n", field_name);
}
}
free(message_copy);
New code that doesn't leak:
const char *message = "From: username\nMessage: basic message\n";
char *message_copy, *freeable_message_copy, *line, *field_name;
int colon_position;
freeable_message_copy = message_copy = strdup(message);
while(line = strsep(&message_copy, "\n")) {
printf(line);
char *colon = strchr(line, ':');
if (colon != NULL) {
colon_position = colon - line;
strncpy(field_name, line, colon_position);
printf("%s\n", field_name);
}
}
free(freeable_message_copy);
How is the message_copy
pointer being overwritten in the first code? or is it?
Because
strsep()
modifies themessage_copy
argument, you were trying to free a pointer that was not returned bymalloc()
et al. This would generate complaints from somemalloc()
libraries, and fromvalgrind
. It is also undefined behaviour, usually leading to crashes in short order (but crashes in code at an inconvenient location unrelated to the code that did the damage).In fact, your loop iterates until
message_copy
is set to NULL, so you were freeing NULL, which is defined and safe behaviour, but it is also a no-op. It did not free the pointer allocated viastrdup()
.Summary:
From the man page,
...This token is terminated by overwriting the delimiter with a null byte ('\0') and
*stringp is updated to point past the token
....The function strsep() takes a pointer to the original string (message_copy) and modifies it to return a new pointer to the 'next' token
Print out the pointer here,
Note that as you use strsep(), you are modifying the message_copy,
This illustrates the changed message_copy, while original_copy is unchanged,
Since message_copy does not point to the original strdup() result this would be wrong,
But keep around the original strdup() result, and this free works
Have a read of the
strsep
man page here.In short the
strsep
function will modify the original character pointer that's passed into the function, overwriting each occurrance of the delimiter with a\0
, and the original character pointer is then updated to point past the\0
.Your second version doesn't leak, as you created a temporary pointer to point to the start of the original char pointer returned from
strdup()
, so the memory was freed correctly, as you calledfree()
with the original char pointer instead of the updated one thatstrsep()
had modified.