Skip to content

Logic bug in toml_parse, causing infinite loop or memory leak #11

@jidnjs

Description

@jidnjs

Description

There are two logic issues in toml_parse:

Case 1: Quoted key is not handled, causing an infinite loop - CRITICAL

toml_parse only treats keys beginning with isalnum, _, or - as valid keys

Quoted keys are valid in TOML, but toml_parse doesn’t handle them and gets stuck in an infinite loop.

Case 2: Early returns due to error do not free the allocated table, causing memory leaks

When toml_parse_table() or toml_parse_key_value() returns an error, toml_parse simply returns NULL without freeing the table allocated at the beginning:

TomlTable* toml_parse(TomlParser *self)
{
    TomlTable *table = NULL;

    table = toml_table_new();

    while (self->ptr < self->end) {
        char ch = *self->ptr;

        while (self->ptr < self->end && isspace(ch)) {
            toml_move_next(self);
            ch = *self->ptr;
        }

        if (ch == '#') {
            do {
                toml_move_next(self);
                ch = *self->ptr;
            } while (self->ptr < self->end && ch != '\n');
            toml_move_next(self);
        } else if (ch == '[') {
            toml_move_next(self);
            if (toml_parse_table(self, table) != 0)
                return NULL; // should free 'table'
        } else if (isalnum(ch) || ch == '_' || ch == '-') { // should not check '-', but should check quotes: '\"', '\''
            if (toml_parse_key_value(self, table) != 0)
                return NULL; // should free 'table'
        } else if (ch == ' ' || ch == '\t' || ch == '\r') {
            do {
                toml_move_next(self);
                ch = *self->ptr;
            } while (ch == ' ' || ch == '\t' || ch == '\r');
        } else if (ch == '\n') {
            toml_move_next(self);
        }
    }

    return table;
}

Reproduction

  1. create file named: repro_logic_bug with one of following contents:

case 1 (infinite loop):

"key" = "infinite loop!"

or

'key' = "infinite loop!"

case 2 (memory leak):

-table_not_freed = "true"
  1. run the parser
toml_load_filename("./repro_logic_bug");

Actual behavior

Case 1: Parser enters an infinite loop and never terminates.
Case 2: toml_load_filename returns NULL without freeing allocated table.

example output:

=================================================================
==21457==ERROR: LeakSanitizer: detected memory leaks

Direct leak of 24 byte(s) in 1 object(s) allocated from:
    #0 0x55d1fd5f8902 in malloc
    #1 0x55d1fd683460 in toml_default_malloc src/toml.c:18:15
    #2 0x55d1fd636c45 in toml_malloc src/toml.c:54:12
    #3 0x55d1fd63c639 in toml_table_new src/toml.c:270:23
    #4 0x55d1fd67f4e3 in toml_parse src/toml.c:1653:13
    #5 0x55d1fd6815bf in toml_load_nstr_filename src/toml.c:1698:13
    #6 0x55d1fd682f7d in toml_load_file_filename src/toml.c:1743:13
    #7 0x55d1fd6832e3 in toml_load_filename src/toml.c:1772:13
    #8 0x55d1fd6366ff in main fuzz_libtoml.c:13:24
    #9 0x7fdf69d301c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #10 0x7fdf69d3028a in __libc_start_main csu/../csu/libc-start.c:360:3
    #11 0x55d1fd55a404 in _start

SUMMARY: AddressSanitizer: 24 byte(s) leaked in 1 allocation(s).

Expected behavior

Case 1: toml_load_filename should parse quoted key normally

Case 2: toml_load_filename should free table and return NULL

Fix suggestion

  • Detect quoted keys (" or ') in the key-value branch.

  • Free allocated table before early return of NULL

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions