Opened 6 years ago
Last modified 5 years ago
#12535 new Bugs
boost::program_options cannot handle std::uint8_t arguments
Reported by: | gilgamash | Owned by: | Vladimir Prus |
---|---|---|---|
Milestone: | To Be Determined | Component: | program_options |
Version: | Boost 1.61.0 | Severity: | Problem |
Keywords: | uint8_t | Cc: |
Description
When using std::uint8_t (and probably std::int8_t as well) as a value type for parameters, the store method crashes with an exception: the argument (value) for option '(option)' is invalid.
Attachments (1)
Change History (3)
comment:1 by , 6 years ago
by , 5 years ago
Attachment: | program_options_uint8_demo.cc added |
---|
reproduce the error (Boost 1.55.0, GCC 4.9.2, Debian 8.8)
comment:2 by , 5 years ago
Compile with:
c++ -std=c++11 -Wall -Wextra -Wold-style-cast -pedantic -ggdb program_options_uint8_demo.cc -lboost_program_options -o program_options_uint8_demo
Run with:
./program_options_uint8_demo
Actual result:
terminate called after throwing an instance of 'boost::exception_detail::clone_impl<boost::exception_detail::error_info_injector<boost::program_options::invalid_option_value> >' what(): the argument ('241') for option '--num' is invalid
Backtrace when the exception is being thrown:
- in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6
- in boost::throw_exception<boost::bad_lexical_cast> (e=...) at /usr/include/boost/throw_exception.hpp:70
- in boost::detail::lexical_cast_do_cast<unsigned char, std::string>::lexical_cast_impl (arg="241") at /usr/include/boost/lexical_cast.hpp:2375
- in boost::lexical_cast<unsigned char, std::string> (arg="241") at /usr/include/boost/lexical_cast.hpp:2543
- in boost::program_options::validate<unsigned char, char> (v=..., xs=std::vector of length 1, capacity 1 = {...}) at /usr/include/boost/program_options/detail/value_semantic.hpp:89
- in boost::program_options::typed_value<unsigned char, char>::xparse (this=0x619070, value_store=..., new_tokens=std::vector of length 1, capacity 1 = {...}) at /usr/include/boost/program_options/detail/value_semantic.hpp:170
- in boost::program_options::value_semantic_codecvt_helper<char>::parse(boost::any&, std::vector<std::string, std::allocator<std::string> > const&, bool) const () from /usr/lib/x86_64-linux-gnu/libboost_program_options.so.1.55.0
- in boost::program_options::store(boost::program_options::basic_parsed_options<char> const&, boost::program_options::variables_map&, bool) () from /usr/lib/x86_64-linux-gnu/libboost_program_options.so.1.55.0
- in main () at program_options_uint8_demo.cc:16
Cause:
lexical_cast sees uint8_t as unsigned char and expects a one-character string, but "241" has three characters. Likewise, --num=9 would set num='9', i.e. num=57 in ASCII, not num=9.
Rationale:
I expect value<char> to parse a one-character argument; if that were changed to parse an integer, it would be too surprising.
OTOH, options that require a one-character argument and save that as char don't seem very useful nowadays, because of multibyte characters.
If value<char> parses a one-character argument, and int8_t is defined as char (rather than signed char), then value<int8_t> is undistinguishable from value<char> and must likewise parse a one-character argument.
If value<char> parsed a one-character argument but value<unsigned char> were changed to parse an integer, that would be an annoying asymmetry.
Passing arbitrary raw bytes as unsigned char in the command line is not feasible because argv[] does not support null bytes and Windows always requires a conversion from UTF-16.
Recommendation for programs:
Define the argument type as a string if you want a single character, and as int if you want an 8-bit integer. Then separately check that the string isn't too long or that the integer isn't out of range.
Recommendation for Boost:
Keep value<char> and value<unsigned char> parsing a single-character argument like now, but change the error message to say that the argument is too long and a single character was expected. This will make it easier for the programmer to understand how to fix the problem if integer parsing was intended.
Perhaps add separate integer_value functions that support uint8_t and allow the programmer to specify the permitted range of integers.
Please provide a complete minimal example that shows this problem. Thanks!