When a symbol that is already registered is read again from *.symref file, __add_symbol() removes the previous one from the hash table without freeing it. [Test Case] $ cat foo.c #include <linux/export.h> void foo(void); void foo(void) {} EXPORT_SYMBOL(foo); $ cat foo.symref foo void foo ( void ) foo void foo ( void ) When a symbol is removed from the hash table, it must be freed along with its ->name and ->defn members. However, sym->name cannot be freed because it is sometimes shared with node->string, but not always. If sym->name and node->string share the same memory, free(sym->name) could lead to a double-free bug. To resolve this issue, always assign a strdup'ed string to sym->name.
Showing the changes to scripts (3 of 3 files). Show all
Unified · Split
| @@ -272,11 +272,15 @@ static struct symbol *__add_symbol(const char *name, enum symbol_type type, · 271 unmodified lines | ||
| 272 | 272 | break; |
| 273 | 273 | } |
| 274 | 274 | } |
| 275 | + | |
| 276 | + free_list(sym->defn, NULL); | |
| 277 | + free(sym->name); | |
| 278 | + free(sym); | |
| 275 | 279 | --nsyms; |
| 276 | 280 | } |
| 277 | 281 | |
| 278 | 282 | sym = xmalloc(sizeof(*sym)); |
| 279 | − sym->name = name; | |
| 283 | + sym->name = xstrdup(name); | |
| 280 | 284 | sym->type = type; |
| 281 | 285 | sym->defn = defn; |
| 282 | 286 | sym->expansion_trail = NULL; |
| @@ -483,7 +487,7 @@ static void read_reference(FILE *f) · 200 unmodified lines | ||
| 483 | 487 | defn = def; |
| 484 | 488 | def = read_node(f); |
| 485 | 489 | } |
| 486 | − subsym = add_reference_symbol(xstrdup(sym->string), sym->tag, | |
| 490 | + subsym = add_reference_symbol(sym->string, sym->tag, | |
| 487 | 491 | defn, is_extern); |
| 488 | 492 | subsym->is_override = is_override; |
| 489 | 493 | free_node(sym); |
| @@ -32,7 +32,7 @@ struct string_list { · 31 unmodified lines | ||
| 32 | 32 | |
| 33 | 33 | struct symbol { |
| 34 | 34 | struct symbol *hash_next; |
| 35 | − const char *name; | |
| 35 | + char *name; | |
| 36 | 36 | enum symbol_type type; |
| 37 | 37 | struct string_list *defn; |
| 38 | 38 | struct symbol *expansion_trail; |
| @@ -482,12 +482,12 @@ enumerator_list: · 481 unmodified lines | ||
| 482 | 482 | enumerator: |
| 483 | 483 | IDENT |
| 484 | 484 | { |
| 485 | − const char *name = strdup((*$1)->string); | |
| 485 | + const char *name = (*$1)->string; | |
| 486 | 486 | add_symbol(name, SYM_ENUM_CONST, NULL, 0); |
| 487 | 487 | } |
| 488 | 488 | | IDENT '=' EXPRESSION_PHRASE |
| 489 | 489 | { |
| 490 | − const char *name = strdup((*$1)->string); | |
| 490 | + const char *name = (*$1)->string; | |
| 491 | 491 | struct string_list *expr = copy_list_range(*$3, *$2); |
| 492 | 492 | add_symbol(name, SYM_ENUM_CONST, expr, 0); |
| 493 | 493 | } |