Skip to content

doc: document config_setting_t pointer invalidation on override and re-read (#298) - #300

Merged
hyperrealm merged 2 commits into
hyperrealm:masterfrom
SergioAtienza:docs/setting-pointer-invalidation-298
Sep 28, 2026
Merged

hyperrealm merged 2 commits into
hyperrealm:masterfrom
SergioAtienza:docs/setting-pointer-invalidation-298

Conversation

@SergioAtienza

Copy link
Copy Markdown
Contributor

Summary

Documentation-only fix for #298, implementing the approach agreed upon in the issue discussion (documenting the invalidation rules; a behavioral reuse-in-place fix was considered and set aside because pointers to children of a replaced setting would dangle in the same way).

Two undocumented invalidation rules currently leave config_setting_t * handles dangling:

  1. Override path: with CONFIG_OPTION_ALLOW_OVERRIDES enabled, config_setting_add() with a duplicate name internally calls config_setting_remove(), which recursively destroys the pre-existing setting object (__config_setting_destroy()). Any pointer previously returned for that setting or its children is left dangling, and its next use is a heap-use-after-free (CWE-416) — see the ASan trace in heap-use-after-free: config_setting_add() with CONFIG_OPTION_ALLOW_OVERRIDES silently destroys the existing setting, leaving callers with dangling pointers #298.
  2. Re-read path: all three config_read*() entry points route through __config_read(), which calls config_clear() before parsing, recursively destroying the entire existing setting tree. Any pointer obtained before a re-read (the classic daemon-reload-on-SIGHUP pattern) silently dangles; none of the three manual entries mentioned this.

Changes (doc/libconfig.texi only, no code changes)

  • CONFIG_OPTION_ALLOW_OVERRIDES: note that overriding destroys the previous setting object (recursively, including any children) and invalidates all pointers previously returned for it, e.g. by config_setting_add(), config_setting_get_member(), or config_lookup().
  • config_setting_add(): clarify that the "already exists" NULL return applies when CONFIG_OPTION_ALLOW_OVERRIDES is turned off, and that when it is on the existing child setting is destroyed and replaced, invalidating previously returned pointers.
  • config_read(), config_read_file(), config_read_string(): note that reading into a configuration discards any previously read configuration — all settings are recursively destroyed first (as with config_clear()) — so previously returned pointers become invalid and must not be used.

The wording follows the patches posted and discussed in #298, rebased onto current master (277b960; context had shifted slightly after #297).

Verification

  • Both statements were cross-checked against lib/libconfig.c on current master: the override path (config_setting_add() → config_setting_remove() → __config_setting_destroy()) and the re-read path (config_read*() → __config_read() → config_clear()).
  • makeinfo --no-split doc/libconfig.texi and makeinfo --html --no-split doc/libconfig.texi both build cleanly: no errors and no new warnings (the only warning, node `Lookup Differences' unreferenced, already exists on master and was introduced by docs: document differences between config_lookup and typed lookups (#242) #297). All five added notes were confirmed present in the rendered info and HTML output.

If you would like the same note added to the corresponding C++ API entries (Config::OptionAllowOverrides, Setting::add(), Config::read()/readFile()/readString()), I'm happy to include it here or in a follow-up PR.

Fixes #298


Discovered with DarwinFuzz — Sergio Atienza Pastor, R&D department of MTP (Métodos y Tecnología) and UPM (Universidad Politécnica de Madrid). Full report and ASan trace in #298.

…VERRIDES)

When CONFIG_OPTION_ALLOW_OVERRIDES is enabled, config_setting_add()
with a duplicate name internally calls config_setting_remove(), which
recursively destroys the pre-existing setting object before the
replacement is created. Any config_setting_t pointer previously
returned for the overridden setting or its children is left dangling,
and its next use is a use-after-free.

Document this invalidation rule in the CONFIG_OPTION_ALLOW_OVERRIDES
and config_setting_add() manual entries.

Refs hyperrealm#298
config_read(), config_read_file() and config_read_string() all route
through __config_read(), which calls config_clear() before parsing,
recursively destroying the entire existing setting tree. Any
config_setting_t pointer obtained before a re-read (a common pattern
in daemons reloading configuration on SIGHUP) is left dangling.

Add the corresponding note to the three manual entries.

Refs hyperrealm#298
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants