Opened 13 years ago

Closed 13 years ago

#4008 closed Bugs (invalid)

Segfault in program_options::parse_command_line when compiled with -fshort-enums

Reported by: Severin Kacianka <severin@…> Owned by: Vladimir Prus
Milestone: Boost 1.43.0 Component: program_options
Version: Boost 1.42.0 Severity: Showstopper
Keywords: Cc:

Description

Hello,

I am new to C++ and bug finding in general, so I hope am not reporting something obvious. When diving into program_options I wrote the following sample program:

// test.cpp
#include <boost/program_options.hpp> 
#include <iostream>
#include <fstream>

namespace po = boost::program_options; 

int main(int argc, char **argv)
{

    int result = EXIT_SUCCESS;
	po::options_description desc("Allowed options"); 
	desc.add_options()
		("help", "Displays help message")
		("port",po::value<int>(),"Port to use")
	;
	po::options_description cmdline_options;
	cmdline_options.add(desc);
	po::options_description config_file_options;
	config_file_options.add(desc);
	po::variables_map vm;
	po::store(po::parse_command_line(argc, argv, desc), vm);
	po::notify(vm);

	if (vm.count("port")) {
		std::cout << "port was set to " 
		 << vm["port"].as<int>() << ".\n";
	} else {
		std::cout << "port was not set.\n";
	}

	return result;
}

When compiled 'normally' it works:

$ g++  test.cpp -lboost_program_options
$ ./a.out --port 60
port was set to 60.

but when I compile it with -fshort-enums it segfaults:

$ g++ -fshort-enums test.cpp -lboost_program_options
$./a.out 
Segmentation fault

My gcc version:

 g++ -v
Reading specs from /usr/lib/gcc/i486-slackware-linux/4.2.4/specs
Target: i486-slackware-linux
Configured with: ../gcc-4.2.4/configure --prefix=/usr --enable-shared --enable-languages=ada,c,c++,fortran,java,objc --enable-threads=posix --enable-__cxa_atexit --disable-checking --with-gnu-ld --verbose --with-arch=i486 --target=i486-slackware-linux --host=i486-slackware-linux
Thread model: posix
gcc version 4.2.4

Valgrind output of the crashing binary:

valgrind a.out 
==11266== Memcheck, a memory error detector.
==11266== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==11266== Using LibVEX rev 1804, a library for dynamic binary translation.
==11266== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==11266== Using valgrind-3.3.0, a dynamic binary instrumentation framework.
==11266== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==11266== For more details, rerun with: -v
==11266== 
==11266== Conditional jump or move depends on uninitialised value(s)
==11266==    at 0x804EF64: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::clear() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x804EFBC: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::~function1() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x8050AD7: boost::program_options::detail::cmdline::~cmdline() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x8050B6B: boost::program_options::basic_command_line_parser<char>::~basic_command_line_parser() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x8056277: boost::program_options::basic_parsed_options<char> boost::program_options::parse_command_line<char>(int, char**, boost::program_options::options_description const&, int, boost::function1<std::pair<std::string, std::string>, std::string const&>) (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x804DE66: main (in /home/severin/swpr-02/examples/conf/a.out)
==11266== 
==11266== Conditional jump or move depends on uninitialised value(s)
==11266==    at 0x804EF7A: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::clear() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x804EFBC: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::~function1() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x8050AD7: boost::program_options::detail::cmdline::~cmdline() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x8050B6B: boost::program_options::basic_command_line_parser<char>::~basic_command_line_parser() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x8056277: boost::program_options::basic_parsed_options<char> boost::program_options::parse_command_line<char>(int, char**, boost::program_options::options_description const&, int, boost::function1<std::pair<std::string, std::string>, std::string const&>) (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x804DE66: main (in /home/severin/swpr-02/examples/conf/a.out)
==11266== 
==11266== Use of uninitialised value of size 4
==11266==    at 0x804EF39: boost::detail::function::basic_vtable1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::clear(boost::detail::function::function_buffer&) (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x804EF99: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::clear() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x804EFBC: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::~function1() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x8050AD7: boost::program_options::detail::cmdline::~cmdline() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x8050B6B: boost::program_options::basic_command_line_parser<char>::~basic_command_line_parser() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x8056277: boost::program_options::basic_parsed_options<char> boost::program_options::parse_command_line<char>(int, char**, boost::program_options::options_description const&, int, boost::function1<std::pair<std::string, std::string>, std::string const&>) (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x804DE66: main (in /home/severin/swpr-02/examples/conf/a.out)
==11266== 
==11266== Use of uninitialised value of size 4
==11266==    at 0x804EF42: boost::detail::function::basic_vtable1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::clear(boost::detail::function::function_buffer&) (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x804EF99: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::clear() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x804EFBC: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::~function1() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x8050AD7: boost::program_options::detail::cmdline::~cmdline() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x8050B6B: boost::program_options::basic_command_line_parser<char>::~basic_command_line_parser() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x8056277: boost::program_options::basic_parsed_options<char> boost::program_options::parse_command_line<char>(int, char**, boost::program_options::options_description const&, int, boost::function1<std::pair<std::string, std::string>, std::string const&>) (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x804DE66: main (in /home/severin/swpr-02/examples/conf/a.out)
vex x86->IR: unhandled instruction bytes: 0x67 0x5 0x8 0x0
==11266== 
==11266== Invalid read of size 4
==11266==    at 0x805A539: ???
==11266==    by 0x804EF99: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::clear() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x804EFBC: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::~function1() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x8050AD7: boost::program_options::detail::cmdline::~cmdline() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x8050B6B: boost::program_options::basic_command_line_parser<char>::~basic_command_line_parser() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x8056277: boost::program_options::basic_parsed_options<char> boost::program_options::parse_command_line<char>(int, char**, boost::program_options::options_description const&, int, boost::function1<std::pair<std::string, std::string>, std::string const&>) (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x804DE66: main (in /home/severin/swpr-02/examples/conf/a.out)
==11266==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==11266== 
==11266== Process terminating with default action of signal 11 (SIGSEGV)
==11266==  Access not within mapped region at address 0x0
==11266==    at 0x805A539: ???
==11266==    by 0x804EF99: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::clear() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x804EFBC: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::~function1() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x8050AD7: boost::program_options::detail::cmdline::~cmdline() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x8050B6B: boost::program_options::basic_command_line_parser<char>::~basic_command_line_parser() (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x8056277: boost::program_options::basic_parsed_options<char> boost::program_options::parse_command_line<char>(int, char**, boost::program_options::options_description const&, int, boost::function1<std::pair<std::string, std::string>, std::string const&>) (in /home/severin/swpr-02/examples/conf/a.out)
==11266==    by 0x804DE66: main (in /home/severin/swpr-02/examples/conf/a.out)
==11266== 
==11266== ERROR SUMMARY: 5 errors from 5 contexts (suppressed: 23 from 1)
==11266== malloc/free: in use at exit: 568 bytes in 33 blocks.
==11266== malloc/free: 39 allocs, 6 frees, 704 bytes allocated.
==11266== For counts of detected errors, rerun with: -v
==11266== searching for pointers to 33 not-freed blocks.
==11266== checked 119,684 bytes.
==11266== 
==11266== LEAK SUMMARY:
==11266==    definitely lost: 0 bytes in 0 blocks.
==11266==      possibly lost: 136 bytes in 6 blocks.
==11266==    still reachable: 432 bytes in 27 blocks.
==11266==         suppressed: 0 bytes in 0 blocks.
==11266== Rerun with --leak-check=full to see details of leaked memory.
Segmentation fault

If I can help you finding the cause, just write me an e-mail :-)

Change History (6)

comment:1 by Severin Kacianka <severin@…>, 13 years ago

ah, I forgot to add that I use boost version 1.42 and that the bug does not occur on my iBook G4 with gcc 4.01

comment:2 by Severin Kacianka <severin@…>, 13 years ago

Another Addition: I compiled gcc 4.4.3 to see if it is a gcc issue, but I still get the crashes. Here is the valgrind output for the binary compiler with gcc 4.4.3:

$ /home/severin/software/gcc/bin/g++ -fshort-enums -g -Wl,-R,/home/severin/software/gcc/lib test.cpp -lboost_program_options
$ valgrind a.out 
==11870== Memcheck, a memory error detector.
==11870== Copyright (C) 2002-2007, and GNU GPL'd, by Julian Seward et al.
==11870== Using LibVEX rev 1804, a library for dynamic binary translation.
==11870== Copyright (C) 2004-2007, and GNU GPL'd, by OpenWorks LLP.
==11870== Using valgrind-3.3.0, a dynamic binary instrumentation framework.
==11870== Copyright (C) 2000-2007, and GNU GPL'd, by Julian Seward et al.
==11870== For more details, rerun with: -v
==11870== 
==11870== My PID = 11870, parent PID = 11794.  Prog and args are:
==11870==    a.out
==11870== 
--11870-- Warning: DWARF2 CFI reader: unhandled DW_OP_ opcode 0x55
==11870== Conditional jump or move depends on uninitialised value(s)
==11870==    at 0x8050238: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::clear() (function_template.hpp:854)
==11870==    by 0x804F828: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::~function1() (function_template.hpp:752)
==11870==    by 0x804EF85: boost::program_options::detail::cmdline::~cmdline() (cmdline.hpp:54)
==11870==    by 0x804EFEC: boost::program_options::basic_command_line_parser<char>::~basic_command_line_parser() (parsers.hpp:88)
==11870==    by 0x804F097: boost::program_options::basic_parsed_options<char> boost::program_options::parse_command_line<char>(int, char**, boost::program_options::options_description const&, int, boost::function1<std::pair<std::string, std::string>, std::string const&>) (parsers.hpp:121)
==11870==    by 0x804DD3E: main (test.cpp:21)
==11870== 
==11870== Conditional jump or move depends on uninitialised value(s)
==11870==    at 0x805024A: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::clear() (function_template.hpp:855)
==11870==    by 0x804F828: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::~function1() (function_template.hpp:752)
==11870==    by 0x804EF85: boost::program_options::detail::cmdline::~cmdline() (cmdline.hpp:54)
==11870==    by 0x804EFEC: boost::program_options::basic_command_line_parser<char>::~basic_command_line_parser() (parsers.hpp:88)
==11870==    by 0x804F097: boost::program_options::basic_parsed_options<char> boost::program_options::parse_command_line<char>(int, char**, boost::program_options::options_description const&, int, boost::function1<std::pair<std::string, std::string>, std::string const&>) (parsers.hpp:121)
==11870==    by 0x804DD3E: main (test.cpp:21)
==11870== 
==11870== Use of uninitialised value of size 4
==11870==    at 0x8050CAB: boost::detail::function::basic_vtable1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::clear(boost::detail::function::function_buffer&) (function_template.hpp:503)
==11870==    by 0x8050268: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::clear() (function_template.hpp:856)
==11870==    by 0x804F828: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::~function1() (function_template.hpp:752)
==11870==    by 0x804EF85: boost::program_options::detail::cmdline::~cmdline() (cmdline.hpp:54)
==11870==    by 0x804EFEC: boost::program_options::basic_command_line_parser<char>::~basic_command_line_parser() (parsers.hpp:88)
==11870==    by 0x804F097: boost::program_options::basic_parsed_options<char> boost::program_options::parse_command_line<char>(int, char**, boost::program_options::options_description const&, int, boost::function1<std::pair<std::string, std::string>, std::string const&>) (parsers.hpp:121)
==11870==    by 0x804DD3E: main (test.cpp:21)
==11870== 
==11870== Use of uninitialised value of size 4
==11870==    at 0x8050CB4: boost::detail::function::basic_vtable1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::clear(boost::detail::function::function_buffer&) (function_template.hpp:504)
==11870==    by 0x8050268: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::clear() (function_template.hpp:856)
==11870==    by 0x804F828: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::~function1() (function_template.hpp:752)
==11870==    by 0x804EF85: boost::program_options::detail::cmdline::~cmdline() (cmdline.hpp:54)
==11870==    by 0x804EFEC: boost::program_options::basic_command_line_parser<char>::~basic_command_line_parser() (parsers.hpp:88)
==11870==    by 0x804F097: boost::program_options::basic_parsed_options<char> boost::program_options::parse_command_line<char>(int, char**, boost::program_options::options_description const&, int, boost::function1<std::pair<std::string, std::string>, std::string const&>) (parsers.hpp:121)
==11870==    by 0x804DD3E: main (test.cpp:21)
==11870== 
==11870== Jump to the invalid address stated on the next line
==11870==    at 0x8955C3C9: ???
==11870==    by 0x8050268: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::clear() (function_template.hpp:856)
==11870==    by 0x804F828: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::~function1() (function_template.hpp:752)
==11870==    by 0x804EF85: boost::program_options::detail::cmdline::~cmdline() (cmdline.hpp:54)
==11870==    by 0x804EFEC: boost::program_options::basic_command_line_parser<char>::~basic_command_line_parser() (parsers.hpp:88)
==11870==    by 0x804F097: boost::program_options::basic_parsed_options<char> boost::program_options::parse_command_line<char>(int, char**, boost::program_options::options_description const&, int, boost::function1<std::pair<std::string, std::string>, std::string const&>) (parsers.hpp:121)
==11870==    by 0x804DD3E: main (test.cpp:21)
==11870==  Address 0x8955c3c9 is not stack'd, malloc'd or (recently) free'd
==11870== 
==11870== Process terminating with default action of signal 11 (SIGSEGV)
==11870==  Access not within mapped region at address 0x8955C3C9
==11870==    at 0x8955C3C9: ???
==11870==    by 0x8050268: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::clear() (function_template.hpp:856)
==11870==    by 0x804F828: boost::function1<std::vector<boost::program_options::basic_option<char>, std::allocator<boost::program_options::basic_option<char> > >, std::vector<std::string, std::allocator<std::string> >&>::~function1() (function_template.hpp:752)
==11870==    by 0x804EF85: boost::program_options::detail::cmdline::~cmdline() (cmdline.hpp:54)
==11870==    by 0x804EFEC: boost::program_options::basic_command_line_parser<char>::~basic_command_line_parser() (parsers.hpp:88)
==11870==    by 0x804F097: boost::program_options::basic_parsed_options<char> boost::program_options::parse_command_line<char>(int, char**, boost::program_options::options_description const&, int, boost::function1<std::pair<std::string, std::string>, std::string const&>) (parsers.hpp:121)
==11870==    by 0x804DD3E: main (test.cpp:21)
==11870== 
==11870== ERROR SUMMARY: 5 errors from 5 contexts (suppressed: 23 from 1)
==11870== malloc/free: in use at exit: 568 bytes in 32 blocks.
==11870== malloc/free: 38 allocs, 6 frees, 704 bytes allocated.
==11870== For counts of detected errors, rerun with: -v
==11870== searching for pointers to 32 not-freed blocks.
==11870== checked 123,768 bytes.
==11870== 
==11870== LEAK SUMMARY:
==11870==    definitely lost: 0 bytes in 0 blocks.
==11870==      possibly lost: 136 bytes in 6 blocks.
==11870==    still reachable: 432 bytes in 26 blocks.
==11870==         suppressed: 0 bytes in 0 blocks.
==11870== Rerun with --leak-check=full to see details of leaked memory.

comment:3 by Vladimir Prus, 13 years ago

I believe that -fshort-enums changes class layout. Therefore, all modules in your program should be built with the same value of that option. Do you still get the crash if you rebuild Boost with that option?

comment:4 by Severin Kacianka <severin@…>, 13 years ago

sorry for my late reply, but i was very busy this week.

I think you are right. However how do I compile boost with -fshort-enums or check that it compiled with it? Here is what a tried:

$ bjam cxxflags=-fshort-enums --prefix=/home/severin/software/boost_test install
... boost compiles ....
$ g++ -L/home/severin/software/boost_test/lib/ -Wl,-R/home/severin/software/boost_test/lib/ -I/home/severin/software/boost_test/include/ test.cpp -lboost_program_options -fshort-enums
$ ldd a.out 
        linux-gate.so.1 =>  (0xffffe000)
        libboost_program_options.so.1.42.0 => /home/severin/software/boost_test/lib/libboost_program_options.so.1.42.0 (0xb7fbc000)
(... other libs ...)
$ ./a.out 
Segmentation fault

in reply to:  4 comment:5 by Severin Kacianka <severin@…>, 13 years ago

ah I just figured out, that I forgot to rebuild boost.

 bjam cxxflags=-fshort-enums --prefix=/home/severin/software/boost_test install -a

(Note the -a at the end)

now the compilation with -fshot-enums works fine (but of course it crashes if I compile it without -fshort-enums). Sorry that the problem was so trivial - I am very new to C++ and did not expect that a compiler flag can cause a segfault ;-) Thank you for your solution!

comment:6 by Vladimir Prus, 13 years ago

Resolution: invalid
Status: newclosed

Good to know that this issue has been resolved. I'm closing the ticket.

Note: See TracTickets for help on using tickets.