[BusyBox] xfuncts.c xfree() ?
Neal H Walfield
neal at cs.uml.edu
Thu Dec 6 08:27:05 UTC 2001
> If there is a variable that may or may not be assigned data (depending
> on some condition) then its easier to free it unconditionally rather
> than testing it first.
This is completely wrong.
>
> e.g. in unarchival/libunarchive/unarchive.c at the bottom of the file it
> does
>
> free(file_entry->name);
> free(file_entry->link_name);
> free(file_entry);
Good example.
Consider the following:
The first thing that we do in extract_archive is check if prefix is
NULL, if it is not, we set full_name to a fresh allocated buffer,
otherwise, we point it to file_entry->name.
char *extract_archive(FILE *src_stream, FILE *out_stream,
const file_header_t *file_entry,
const int function, const char *prefix)
{
FILE *dst_stream = NULL;
char *full_name = NULL;
char *buffer = NULL;
struct utimbuf t;
/* prefix doesnt have to be a proper path it may prepend
* the filename as well */
if (prefix != NULL) {
/* strip leading '/' in filename to extract as prefix may not be dir */
/* Cant use concat_path_file here as prefix might not be a directory */
char *path = file_entry->name;
if (strncmp("./", path, 2) == 0) {
path += 2;
if (strlen(path) == 0) {
return(NULL);
}
}
full_name = xmalloc(strlen(prefix) + strlen(path) + 1);
strcpy(full_name, prefix);
strcat(full_name, path);
} else {
full_name = file_entry->name;
}
At the end of the function, we unconditionally free full_name:
free(full_name);
return(NULL); /* Maybe we should say if failed */
}
Because we have not kept track of who owns full_name, we may have now
freed file_entry->name. Is this an the correct thing to do? Let's
take a look at a caller of extract_archive, e.g. the same file,
unarchive, line 264:
if (extract_flag == TRUE) {
buffer = extract_archive(src_stream, out_stream, file_entry, extract_function, prefix);
} else {
/* seek past the data entry */
seek_sub_file(src_stream, file_entry->size);
}
free(file_entry->name); /* may be null, but doesn't matter */
free(file_entry->link_name);
free(file_entry);
We call extract_archive and then free file_entry->name, however, this
may have already been freed by extract_archive!
Correct me if my logic is wrong, however, I am not that familiar with
the code.
Not to mention that in the case of returning early, e.g. lines 109,
126, 152, 173 and 184, full_name is _not_ free'd!
> file_entry->link_name as you can guess will only ever have data if the
> file is a sysmlink.
>
> If its wrapped in an if to prevent it from being free'ed if its NULL
> i.e.
>
> if (file_entry->link_name) {
> free(file_entry->link_name);
> }
>
> then it increases the size of the binary for no functional
> advantage.
Well, bothering to set the variable to NULL initially wastes space
too.
More information about the busybox
mailing list