Repository navigation
recreate insert iterator after clear in parse_into sequence handler - #1207
Ramya-9353 wants to merge 1 commit into
Conversation
|
An automated preview of the documentation is available at https://1207.json.prtest2.cppalliance.org/libs/json/doc/html/index.html If more commits are pushed to the pull request, the docs will rebuild at the same URL. 2026-10-05 08:37:46 UTC |
|
GCOVR code coverage report https://1207.json.prtest2.cppalliance.org/gcovr/index.html Build time: 2026-10-05 09:13:10 UTC |
|
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## develop #1207 +/- ##
========================================
Coverage 93.98% 93.98%
========================================
Files 85 85
Lines 8973 8973
========================================
Hits 8433 8433
Misses 540 540
Continue to review full report in Codecov by Harness.
🚀 New features to boost your workflow:
|
|
|
||
| container::flat_set<int> s; | ||
| parse_into(s, "[1,2,3,4]"); | ||
| BOOST_TEST( s.size() == 4 ); |
There was a problem hiding this comment.
What is the significance of this test and the one on line 340 as opposed to the test on line 332?
There was a problem hiding this comment.
They are the two distinct shapes. I checked each one separately against develop (fc70d23, assertions on, under ASan):
- 332, nested target: the inner handler's target is the parent's
next_value_, which the parent moves from and reassigns between elements, so the stored hint ends up pointing into a buffer the container no longer owns. The first abort is on the element after the first non-empty one, so[[1],[2]]already trips it. - 340, non-nested target that already holds elements:
clear()inon_array_beginkeeps the capacity, soend()moves back tobegin()while the hint built in the constructor still points at the old end. - 337 passes on develop on its own. A default-constructed
flat_sethasbegin() == end() == nullptr, so the hint is vacuously in range andinsert_iteratorrefreshes it from the result of the first insert. It is only there to fillsfor 340, matching thestd::vector<int>pair just above it.
If you want it tighter I can drop the check on 337 and leave it as plain setup.
There was a problem hiding this comment.
Yeah, let's do that. Remove the test on 337 and instead simply initialize s with an initializer list.

Repro:
parse_intoaboost::container::flat_set<int>that already holds elements ([1,2,3], then[4]into the same object), or astd::vector<flat_set<int>>from[[1,2],[3,4]]. Debug builds stop on Boost.Container'spriv_in_range_or_end(hint)assertion; withNDEBUG, ASan reports a heap-buffer-overflow read inflat_tree::priv_insert_unique_prepare, reached fromsignal_value. C++23std::flat_setfails the same way.Cause: the sequence handler builds its inserter in the constructor and in
signal_end, but the target is cleared later, inon_array_begin, and a nested target (next_value_) is also moved from and reassigned by the parent between elements. Withoutpush_backthe inserter isstd::inserter(c, c.end()), so the stored hint is already invalid when the first element arrives.std::setstill works (checked with libc++) because itsend()survives both, which is why this went unnoticed.Fix: build the inserter in
on_array_begin, right after the clear, instead of insignal_end. The added test aborts on develop and passes with the change.