roll back Group::Add when duplicate flag detection throws - #196
Merged
Conversation
Owner
|
This looks like a good fix, though with normal use of the library (where any exception in a flag is caught outside the scope of the parser) this wouldn't end up being an issue. This usage here could be useful for specialty cases, though, like wrapping this library from a dynamic language like Lua. Thanks for the PR. |
Contributor
Author
|
Agreed, it mostly bites when the parser outlives a failed registration, so the wrapper case is the realistic one. Thanks for merging. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Dangling child pointer when duplicate detection rejects a flag
Detection runs from the new flag's own constructor, so on a collision the
ParseErroris thrown before that constructor finishes and the flag's storage goes away during the unwind, whileGroup::Addhas already pushed the pointer intochildren. Catching the error and carrying on with the parser is then a use-after-free on the nextReset,ParseorHelp.ArgumentParser::AddCompletionhas the same shape at a second site: it took the pointer before callingAdd, so a rejectedCompletionFlagleftArgumentParser::completiondangling too. Assigning afterAddsucceeds looks sufficient there, sinceAddnever reads it.Reproduction
Built with
-fsanitize=addressagainst master:The
AddCompletionhalf is needed on its own. Swapping the duplicateFlagabove fornew args::CompletionFlag(parser, {"alpha"})and applying only theGroup::Addchange still reports a use-after-free, this time oncompletion->Matched()inParse. Both variants run clean with the two together.test/duplicate_flag_rollback.cxxcovers the part that is visible without a sanitiser: the group no longer keeps the rejected child, and the parser still parses afterwards. It fails on master.Detection cannot throw under
ARGS_NOEXCEPT, where it flags a usage error and the child is fully constructed, so the rollback sits behind#ifndef ARGS_NOEXCEPTand the-fno-exceptionsbuild is unaffected.