Opened 7 years ago

Last modified 7 years ago

#11935 new Bugs

boost::program_options::error_with_option_name.what() throws std::out_of_range when an empty option is used in the command input

Reported by: mark.incley@… Owned by: Vladimir Prus
Milestone: To Be Determined Component: program_options
Version: Boost 1.60.0 Severity: Problem
Keywords: program_options Cc:

Description

Hi,

After accidentally typing "-v . -" (without the quotes) into a Windows command line app written with boost::po, it crashed. The app's catch block (code below) calls boost::po::error_with_option_name.what() and this subsequently throws std::out_of_range().

It appears as though the empty option "-" confuses boost::program_options::strip_prefixes(const std::string& text) which is called with text value of "-", resulting in text.substr being called with a value of npos:

  inline std::string strip_prefixes(const std::string& text)
    {
        // "--foo-bar" -> "foo-bar"[[BR]]
        return text.substr(text.find_first_not_of("-/"));
    }

Here's my code.

po::variables_map vm;
	po::options_description desc("Options");
	desc.add_options()
		("folder,f",	po::wvalue<wstring>()->required(), "Specify the name of the folder containing the C++ projects to check")
		("list,l",		"List the project file names as they're checked")
		("verbose,v",	"Verbose; Show the node values when finding non-SAK SCC values")
		("help,?",		"Show usage information")
		;

	po::positional_options_description pod;
	pod.add("folder", -1);

	try
	{
		po::store(po::wcommand_line_parser(argc, argv).options(desc).positional(pod).run(), vm);
		po::notify(vm);
	}
	catch (const boost::program_options::error & e)
	{
		cerr << w32::fg_red << e.what() << w32::restore << endl;
		return ERROR_UNHANDLED_EXCEPTION;
	}

I am using Boost 1.60 on Windows 7 (64-bit) with Visual Studio 2015 Update 1.

Cheers
Mark.

Change History (1)

comment:1 by ghickey@…, 7 years ago

I just ran into this problem too, though in my case I didn't pass in an empty option. I was testing a parameter with a length validator:

add_options()
        ("name", validated<string>(&m_name, length_max(64))->required(), "thing name")

When passed a value longer than the limit the code threw a boost::program_options::error_with_option_name, as expected. Calling that exception's what() method crashed the program in the same way as the original reporter of this bug described, except that in this case the "original_token" value in the error's m_substitutions map was empty. When passed an empty string, strip_prefixes() throws the same out_of_range exception as above.

The following patch will fix the problem:

--- a/boost/program_options/errors.hpp	2013-12-04 00:17:17.000000000 -0500
+++ b/boost/program_options/errors.hpp	2016-01-28 20:03:12.994847938 -0500
@@ -26,7 +26,10 @@
     inline std::string strip_prefixes(const std::string& text)
     {
         // "--foo-bar" -> "foo-bar"
-        return text.substr(text.find_first_not_of("-/"));
+        size_t pos = text.find_first_not_of("-/");
+        if (pos == std::string::npos)
+            return std::string();
+        return text.substr(pos);
     }
 
     /** Base class for all errors in the library. */

I'm using boost 1.58 on Linux.

Note: See TracTickets for help on using tickets.