Skip to content

session_setstr removes from wrong hash table, causing stale reads #2

@rtdean

Description

@rtdean

session_setstr in session.c attempts to remove the old entry before adding the new one, but it removes from session.nums instead of session.strs:

mailfront/session.c

Lines 118 to 124 in 07d683b

void session_setstr(const char* name, const char* value)
{
/* FIXME: use _set when bglibs 1.103 is released */
session_strs_remove(&session.nums, &name);
if (session_strs_add(&session.strs, &name, &value) == 0)
die_oom(111);
}

Compare with session_setnum, which is correct:

mailfront/session.c

Lines 144 to 150 in 07d683b

void session_setnum(const char* name, unsigned long value)
{
/* FIXME: use _set when bglibs 1.103 is released */
session_nums_remove(&session.nums, &name);
if (session_nums_add(&session.nums, &name, &value) == 0)
die_oom(111);
}

When session_setstr is called for a key that already exists, the remove is a no-op (the key isn't in session.nums). The subsequent session_strs_add calls ghash_add, which does not check for duplicates — it inserts a second entry at the next available slot via linear probing. session_getstr calls ghash_find, which scans forward from the hash position and returns the first match — i.e., the original (stale) entry, not the newly added one.

The result is that session_setstr silently fails to update: the old value is returned by all subsequent session_getstr calls, and duplicate entries accumulate in the hash table.

A workaround does exist; by calling session_delstr(name) before session_setstr(name, value). session_delstr correctly removes from session.strs.

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