Boost C++ Libraries: Ticket #12535: boost::program_options cannot handle std::uint8_t arguments https://svn.boost.org/trac10/ticket/12535 <p> 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. </p> en-us Boost C++ Libraries /htdocs/site/boost.png https://svn.boost.org/trac10/ticket/12535 Trac 1.4.3 Vladimir Prus Wed, 21 Dec 2016 11:57:15 GMT <link>https://svn.boost.org/trac10/ticket/12535#comment:1 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12535#comment:1</guid> <description> <p> Please provide a complete minimal example that shows this problem. Thanks! </p> </description> <category>Ticket</category> </item> <item> <author>Kalle Olavi Niemitalo <kon@…></author> <pubDate>Sat, 08 Jul 2017 11:35:12 GMT</pubDate> <title>attachment set https://svn.boost.org/trac10/ticket/12535 https://svn.boost.org/trac10/ticket/12535 <ul> <li><strong>attachment</strong> → <span class="trac-field-new">program_options_uint8_demo.cc</span> </li> </ul> <p> reproduce the error (Boost 1.55.0, GCC 4.9.2, Debian 8.8) </p> Ticket Kalle Olavi Niemitalo <kon@…> Sat, 08 Jul 2017 11:59:41 GMT <link>https://svn.boost.org/trac10/ticket/12535#comment:2 </link> <guid isPermaLink="false">https://svn.boost.org/trac10/ticket/12535#comment:2</guid> <description> <h2 class="section" id="Compilewith:">Compile with:</h2> <p> c++ -std=c++11 -Wall -Wextra -Wold-style-cast -pedantic -ggdb program_options_uint8_demo.cc -lboost_program_options -o program_options_uint8_demo </p> <h2 class="section" id="Runwith:">Run with:</h2> <p> ./program_options_uint8_demo </p> <h2 class="section" id="Actualresult:">Actual result:</h2> <pre class="wiki">terminate called after throwing an instance of 'boost::exception_detail::clone_impl&lt;boost::exception_detail::error_info_injector&lt;boost::program_options::invalid_option_value&gt; &gt;' what(): the argument ('241') for option '--num' is invalid </pre><h2 class="section" id="Backtracewhentheexceptionisbeingthrown:">Backtrace when the exception is being thrown:</h2> <ol start="0"><li> in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 </li><li> in boost::throw_exception&lt;boost::bad_lexical_cast&gt; (e=...) at /usr/include/boost/throw_exception.hpp:70 </li><li> in boost::detail::lexical_cast_do_cast&lt;unsigned char, std::string&gt;::lexical_cast_impl (arg="241") at /usr/include/boost/lexical_cast.hpp:2375 </li><li> in boost::lexical_cast&lt;unsigned char, std::string&gt; (arg="241") at /usr/include/boost/lexical_cast.hpp:2543 </li><li> in boost::program_options::validate&lt;unsigned char, char&gt; (v=..., xs=std::vector of length 1, capacity 1 = {...}) at /usr/include/boost/program_options/detail/value_semantic.hpp:89 </li><li> in boost::program_options::typed_value&lt;unsigned char, char&gt;::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 </li><li> in boost::program_options::value_semantic_codecvt_helper&lt;char&gt;::parse(boost::any&amp;, std::vector&lt;std::string, std::allocator&lt;std::string&gt; &gt; const&amp;, bool) const () from /usr/lib/x86_64-linux-gnu/libboost_program_options.so.1.55.0 </li><li> in boost::program_options::store(boost::program_options::basic_parsed_options&lt;char&gt; const&amp;, boost::program_options::variables_map&amp;, bool) () from /usr/lib/x86_64-linux-gnu/libboost_program_options.so.1.55.0 </li><li> in main () at program_options_uint8_demo.cc:16 </li></ol><h2 class="section" id="Cause:">Cause:</h2> <p> 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. </p> <h2 class="section" id="Rationale:">Rationale:</h2> <p> I expect value&lt;char&gt; to parse a one-character argument; if that were changed to parse an integer, it would be too surprising. </p> <p> OTOH, options that require a one-character argument and save that as char don't seem very useful nowadays, because of multibyte characters. </p> <p> If value&lt;char&gt; parses a one-character argument, and int8_t is defined as char (rather than signed char), then value&lt;int8_t&gt; is undistinguishable from value&lt;char&gt; and must likewise parse a one-character argument. </p> <p> If value&lt;char&gt; parsed a one-character argument but value&lt;unsigned char&gt; were changed to parse an integer, that would be an annoying asymmetry. </p> <p> 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. </p> <h2 class="section" id="Recommendationforprograms:">Recommendation for programs:</h2> <p> 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. </p> <h2 class="section" id="RecommendationforBoost:">Recommendation for Boost:</h2> <p> Keep value&lt;char&gt; and value&lt;unsigned char&gt; 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. </p> <p> Perhaps add separate integer_value functions that support uint8_t and allow the programmer to specify the permitted range of integers. </p> </description> <category>Ticket</category> </item> </channel> </rss>