Skip to content

Don't let the XML input archive destructor throw at end of input#349

Merged
gennaroprota merged 2 commits into
developfrom
fix/xml-iarchive-eof-handling
Jul 21, 2026
Merged

Don't let the XML input archive destructor throw at end of input#349
gennaroprota merged 2 commits into
developfrom
fix/xml-iarchive-eof-handling

Conversation

@gennaroprota

@gennaroprota gennaroprota commented Jul 20, 2026

Copy link
Copy Markdown
Collaborator

An XML input archive whose stream reaches end of input during windup() (run from the destructor) no longer throws, which, from an implicitly noexcept destructor, was calling std::terminate/abort.

Root cause

windup() calls my_parse(). Boost 1.66 (commit 64dc620, whose real purpose was dropping a <codecvt> dependency) changed my_parse() from returning false on a stream fail() to throwing input_stream_error:

is.get(result);
if(is.fail())
    return false;      // <= 1.65
// vs
if(is.fail())
    throw ...;         // 1.66+

get() sets both failbit and eofbit at end of input, and the check tested fail() before eof(). So simply reaching the end while scanning for a tag threw; and since that happens inside the destructor's windup(), the exception escaped the noexcept destructor and terminated the process.

The close tag can be absent at that point for several reasons, which is why this surfaced as three separate reports:

Issues

Fixes #99 (same root cause as the already-closed #82).

It also removes the process-terminating crash reported in #109, but not that issue's broader "broken state after an exception": a failed read still consumes input and leaves the archive unusable, which is a separate, by-design limitation of the forward-only positional parse (you can't probe for an absent named element without consuming input). So this only refs #109 rather than closing it; we can later decide whether #109 should be closed as "crash fixed, remainder by design" or kept open.

@gennaroprota
gennaroprota force-pushed the fix/xml-iarchive-eof-handling branch from a07c613 to b2cd58a Compare July 20, 2026 14:15
The xml input archive destructor calls `windup()` to consume the
trailing tag; `windup()` calls `my_parse()`. Since Boost 1.66 (commit
64dc620), `my_parse()` threw `input_stream_error` whenever `get()` set
`failbit`. But `get()` sets both `failbit` and `eofbit` at end of input,
and the check tested `fail()` before `eof()`---so simply reaching the
end while scanning for a tag threw, escaping the implicitly noexcept
destructor and terminating the process. No closing tag is left to find
in several cases: a truncated stream, an archive whose writer was never
flushed, or a well-formed one whose closing tag an earlier failed read
had already consumed.

So, test `eof()` before `fail()` and return `false` for end of
input---as it did before 1.66 (a genuine, non-EOF stream error still
throws).

As defense in depth, this also wraps the `windup()` call in both XML
input destructors so no exception can escape them regardless.

Fixes issue #99, the same defect as the already-closed #82.

It also removes the terminate reported in #109, though that issue's
broader broken-state-after-exception concern is a by-design limitation
of the forward-only parse and isn't fixed.

Refs #109.
Issue #109 is the same Boost 1.66 `my_parse` regression as #82 and #99,
reached by a different path: reading an nvp that is not present fails
and consumes the closing tag, so at destruction `windup()` meets end of
input and (before the fix) threw out of the noexcept destructor,
terminating the process.

The `my_parse` fix already resolves it; this adds the guarding test. It
reads a value, then a missing nvp (catching the exception), and lets the
archive destruct: it aborts before the fix and passes after.

Refs issue #109.
@gennaroprota
gennaroprota force-pushed the fix/xml-iarchive-eof-handling branch from b2cd58a to 7135618 Compare July 20, 2026 14:27
@gennaroprota gennaroprota changed the title Don't let the XML input archive destructor throw on truncated input Don't let the XML input archive destructor throw at end of input Jul 20, 2026
@gennaroprota
gennaroprota added this pull request to the merge queue Jul 21, 2026
Merged via the queue into develop with commit 432ef2e Jul 21, 2026
43 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.

~xml_iarchive throws exception when input stream is almost empty xml_iarchive destructor calls abort()

1 participant