From 18bd052f11a08becbac24c5b4bdad18405d94149 Mon Sep 17 00:00:00 2001 From: Daniel Bodorin Date: Mon, 23 Mar 2026 16:58:59 +0200 Subject: [PATCH] fix: lower TOML_MAX_NESTED_VALUES to prevent stack overflow in sanitizer builds Deeply nested arrays ([[[...) or inline tables ({a={b={c=...) cause parse_array/parse_inline_table recursion that overflows the stack before the existing TOML_MAX_NESTED_VALUES limit (256) is reached in sanitizer-instrumented builds (ASAN/MSAN), where each recursion cycle consumes ~3KB of stack. Lower the default from 256 to 128. At 128 levels the worst-case stack usage is ~420KB, leaving ample headroom on 1MB stacks even under ASAN. No real TOML document needs 128 levels of container nesting. Also add a regression test for deeply nested inline tables (arrays were already covered by the issues/100 test). Fixes #292 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- CHANGELOG.md | 1 + README.md | 1 + include/toml++/impl/preprocessor.hpp | 6 ++++-- tests/user_feedback.cpp | 12 ++++++++++++ toml.hpp | 6 ++++-- 5 files changed, 22 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 992f1c32..c9155779 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,7 @@ template: - fixed `is_homogeneous()` overloads with `first_nonmatch` outparam being broken in optimized builds (#231) (@Forbinn) - fixed unclear error message when parsing integers that would overflow (#224) (@chrimbo) - fixed CMake `install` target installing `meson.build` files (#236) (@JWCS) +- lowered `TOML_MAX_NESTED_VALUES` default from 256 to 128 to prevent stack overflow on deeply nested arrays/inline tables in sanitizer builds (@danielbodorin) ## v3.4.0 diff --git a/README.md b/README.md index 1e8e2f7e..1539a198 100644 --- a/README.md +++ b/README.md @@ -288,6 +288,7 @@ UTF-8 decoding is performed using a state machine based on Bjoern Hoehrmann's '[ - **[@bjadamson](https://github.com/bjadamson)** - Reported some bugs and helped design a new feature - **[@bobfang1992](https://github.com/bobfang1992)** - Reported a bug and created a [wrapper in python](https://github.com/bobfang1992/pytomlpp) - **[@capuanob](https://github.com/capuanob)** - Integrated this project into OSSFuzz +- **[@danielbodorin](https://github.com/danielbodorin)** - Fixed stack overflow from deeply nested arrays/inline tables - **[@GiulioRomualdi](https://github.com/GiulioRomualdi)** - Added cmake+meson support - **[@jonestristand](https://github.com/jonestristand)** - Designed and implemented the `toml::path`s feature - **[@kcsaul](https://github.com/kcsaul)** - Fixed a bug diff --git a/include/toml++/impl/preprocessor.hpp b/include/toml++/impl/preprocessor.hpp index ff2ce6dd..d74d2b61 100644 --- a/include/toml++/impl/preprocessor.hpp +++ b/include/toml++/impl/preprocessor.hpp @@ -1177,9 +1177,11 @@ #endif #ifndef TOML_MAX_NESTED_VALUES -#define TOML_MAX_NESTED_VALUES 256 +#define TOML_MAX_NESTED_VALUES 128 // this refers to the depth of nested values, e.g. inline tables and arrays. -// 256 is crazy high! if you're hitting this limit with real input, TOML is probably the wrong tool for the job... +// 128 is very generous; real TOML files rarely exceed single-digit nesting. +// keep this value low enough to avoid stack overflows in sanitizer-instrumented builds +// where each recursion cycle may consume ~3KB of stack. #endif #ifndef TOML_MAX_DOTTED_KEYS_DEPTH diff --git a/tests/user_feedback.cpp b/tests/user_feedback.cpp index 6cc1fd34..aa1f36b1 100644 --- a/tests/user_feedback.cpp +++ b/tests/user_feedback.cpp @@ -168,6 +168,18 @@ b = [] constexpr auto start = "fl =[ "sv; memcpy(s.data(), start.data(), start.length()); parsing_should_fail(FILE_LINE_ARGS, std::string_view{ s }); + + // deeply nested inline tables should also fail gracefully, not stack overflow + { + // build: fl = {a={a={a={a=...{a=1}...}}} + std::string nested_tables = "fl = "; + for (size_t i = 0; i < 2048; i++) + nested_tables += "{a="; + nested_tables += "1"; + for (size_t i = 0; i < 2048; i++) + nested_tables += "}"; + parsing_should_fail(FILE_LINE_ARGS, std::string_view{ nested_tables }); + } } SECTION("tomlplusplus/issues/112") // https://github.com/marzer/tomlplusplus/issues/112 diff --git a/toml.hpp b/toml.hpp index c01a208f..5f750cbf 100644 --- a/toml.hpp +++ b/toml.hpp @@ -1086,9 +1086,11 @@ #endif #ifndef TOML_MAX_NESTED_VALUES -#define TOML_MAX_NESTED_VALUES 256 +#define TOML_MAX_NESTED_VALUES 128 // this refers to the depth of nested values, e.g. inline tables and arrays. -// 256 is crazy high! if you're hitting this limit with real input, TOML is probably the wrong tool for the job... +// 128 is very generous; real TOML files rarely exceed single-digit nesting. +// keep this value low enough to avoid stack overflows in sanitizer-instrumented builds +// where each recursion cycle may consume ~3KB of stack. #endif #ifndef TOML_MAX_DOTTED_KEYS_DEPTH