Skip to content

Close 0002: guard the expected-lite selection, run reflected JSON iteration under ASan - #489

Merged
rmorozov merged 2 commits into
masterfrom
claude/project-thread-2eyl7o
Oct 12, 2026
Merged

rmorozov merged 2 commits into
masterfrom
claude/project-thread-2eyl7o

Conversation

@rmorozov

Copy link
Copy Markdown
Member

Requested by Ruslan · project thread

Before: task 0002 reported a segfault when iterating an nlohmann::json array passed through Reflect, with no root cause. No test iterated reflected JSON arrays, and no sanitizer job built the nlohmann bindings. A consumer compiled at C++23 without the CMake/pkg-config flag could silently get std::expected as jinja2::Result<T> while the library uses nonstd::expected.

After: the cause is identified and its remaining instance is closed. template.h defaults expected-lite to its own nonstd::expected and stops with #error when std::expected was already selected in the translation unit. A new test covers iterating reflected arrays, and it runs under ASan+UBSan in CI.

Root cause. This was not a lifetime bug. Before 2.0 the library was built as C++14, so optional-lite and variant-lite used their own types. The probe driver was C++17, where the same headers alias std::optional/std::variant. CreateEnumerator() returns optional<ListEnumeratorPtr>, which the header-only nlohmann accessor and the compiled GenericListAdapter then read with two different layouts. I reproduced it on f2c05c0 by linking a C++17 test object against the C++14 library: UBSan reports load of value 64, which is not a valid value for type 'bool' in nonstd/optional.hpp and every loop renders empty. When both sides use the same standard the test is clean, on f2c05c0 and on master. 0071 (std vocabulary types, C++17 floor) removed the cause. Only the expected selection was still left open.

How.

  • include/jinja2cpp/template.h: #ifndef nsel_CONFIG_SELECT_EXPECTED sets it to NONSTD, then the include, then #if nsel_USES_STD_EXPECTED triggers the #error. Builds through the CMake target or pkg-config already pass NONSTD and are unaffected.
  • test/binding/nlohmann_json_binding_test.cpp: NlohmannJsonTest.ArrayIteration covers top-level, nested, if-filtered and filter-consumed (join, map) iteration. Its output matches Python Jinja2 on the same data.
  • .github/workflows/linux-build.yml: the sanitizer matrix gets a bindings axis. The clang-18 address+undefined job now builds with nlohmann, the gcc-14 ASan and TSan jobs stay on boost, and job names are unchanged.
  • docs/tasks/0002: marked done with the root cause.

Agent notes. Roles: verifier (1 round, no blocking findings). I applied its one nit: the test now uses o['values'], because in Python o.values is dict.values. Red pushes so far: 0. Checks run locally: full suite under clang-18 ASan+UBSan with nlohmann bindings, scripts/preflight.sh, and a gcc-14/clang-18 C++17/C++23 syntax matrix for the header guard. MSVC and the shared-library build were not run here; CI covers them.

🤖 Generated with Claude Code

https://claude.ai/code/session_01URYuQSkLMNwHqGAcDqQZjq


Generated by Claude Code

…eration under ASan

The 0002 segfault was an ABI mismatch, not a lifetime bug: a C++14 library
(nonstd optional/variant) read by a C++17 consumer (std aliases). 2.0 removed
it; Result<T>'s expected-lite selection was the remaining instance, so
template.h now defaults it and rejects std::expected with #error.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01URYuQSkLMNwHqGAcDqQZjq
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01URYuQSkLMNwHqGAcDqQZjq
@rmorozov rmorozov self-assigned this Oct 12, 2026
@rmorozov
rmorozov marked this pull request as ready for review October 12, 2026 13:57
@rmorozov
rmorozov merged commit 5806e40 into master Oct 12, 2026
66 of 76 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants