Skip to content

Invalid command line containing "%canonical_option%" causes hang when what() invoked on resulting exception. #163

Closed

Description

@tbrightbill

Tested on program_options from boost 1.91.0, built on linux with g++ 13.3.0 on Ubuntu subsystem on Windows. Tested as well with program_options 1.81.0 on windows compiled with vc17, and found to be impacted.

During fuzzing, found that providing the option
-%canonical_option%
will cause a hang in any program that uses program_options and uses err.what() to print the invalid argument. My assumption is the field %canonical_option% is used in a string used in error reporting, and is repeatedly replaced with the user's invalid argument. If the user's invalid argument contains this magic string, the attempted replacements will continue forever.

Additionally, strings appended onto the end of this invalid argument will cause increasing memory usage, likely eventually running out of memory. I do not know the behavior in this case - if what() has additional error handling to catch a memory allocation failure, and the program will recover, or if this will result in a crash. The memory consumption appears to grow linearly - even providing multiple %canonical_option% flags, e.g. -%canonical_option%%canonical_option%%canonical_option%` seems to only cause linear growth in memory usage as the program runs. There may be additional substitutions that could be affected, but this is the only one that my fuzzing found.

Security implications: Generally, program_options is only used for processing command lines, so this only affects machines where a malicious actor can run a command line, or inject arguments that end up on a command line. Generally, the only program affected is the program launched, but there are cases where the command line may be passed to a service which then does the parsing, possibly logging any error codes. In such cases, long running services can be caused to have an infinitely looping thread, which continuously allocates memory.

Example program reproducing this hang:
`
#include "boost/program_options/errors.hpp"
#include

int main()
{
boost::program_options::unknown_option err("-%canonical_option%");
std::cout << err.what() << std::endl;
return 0;
}
`
Program hangs and nothing is printed.

Activity

  1. vprus commented on Oct 29, 2026

    @vprus
    Collaborator

    Thanks for the bug report!

    Are you sure the hang is in program_options and not in the Windows shell?

  2. vprus commented on Oct 29, 2026

    @vprus
    Collaborator

    Confirmed: this is in program_options, not the shell.

    unknown_option("-%canonical_option%").what() begins with "unrecognised option '%canonical_option%'". get_canonical_option_name() returns the original token, so %canonical_option% is replaced by -%canonical_option%. replace_token() then searches from offset zero again, immediately finds the newly inserted placeholder, and repeats forever. Any suffix increases the message on each iteration.

    The minimal fix is to advance the search position past the inserted replacement (pos += to.size()) rather than restarting at zero. An allocation failure inside this loop also occurs from what() (non-throwing), so it is unlikely to be recoverable.

  3. vprus commented on Oct 29, 2026

    @vprus
    Collaborator

    PR #164

  4. vprus commented on Oct 29, 2026

    @vprus
    Collaborator

    Thanks for the report! It should be fixed now.

  5. tbrightbill commented on Oct 30, 2026

    @tbrightbill
    Author

    Thanks for the incredibly rapid fix! That fix looks good to me!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions