boost::program_options generating MLK.MUST in Klocwork - c++

I wrote the following C++ code based on the Boost library to take inputs from command line.
#include <iostream>
#include <boost/program_options.hpp>
#include <boost/format.hpp>
using namespace std;
namespace po = boost::program_options;
int main(int argc, char** argv) {
int party = 2, port = 9999;
string server_ip;
po::options_description desc{"Allowed options"};
desc.add_options() //
("help,h", "produce help message") //
("party,k", po::value<int>(&party)->default_value(1), "party id: 1 for server, 2 for client") //
("port,p", po::value<int>(&port)->default_value(1234), "socket port") //
("server_ip,s", po::value<string>(&server_ip)->default_value("localhost"), "server's IP.");
po::variables_map vm;
try {
po::parsed_options parsed = po::command_line_parser(argc, argv).options(desc).allow_unregistered().run();
po::store(parsed, vm);
if (vm.count("help")) {
cout << desc << endl;
return 0;
}
po::notify(vm);
}catch (po::error& e) {
cout << "ERROR: " << e.what() << endl << endl;
cout << desc << endl;
return -1;
}
cout << party << endl;
cout << port << endl;
cout << server_ip << endl;
}
It works as intended. However, Klocwork reported the following error (I have adjusted the line numbers for this code snippet):
main.cpp:16 MLK.MUST (2:Error) Analyze
Memory leak. Dynamic memory stored in 'po::value<int> ( &party)' allocated through function 'value<int>' at line 14 is lost at line 16
* main.cpp:14: Dynamic memory stored in 'po::value<int> ( &party)' is allocated by calling function 'value<int>'.
* value_semantic.hpp:198: 'r' is allocated by function 'new'.
* main.cpp:16: Dynamic memory stored in 'po::value<int> ( &party)' is lost.
Current status 'Analyze'
I found this old post boost program_options generating a Klocwork MLK.MUST. However, after reading the answer, I still do not know how I can solve this issue.
Another issue reported by Klocwork is 'port' is used uninitialized in this function. It specifically mentions that passing '&port' to 'po::value<int>' does not initialize 'port'. However, after running the code, I see that it does initialize port since the value of port is printed as 1234 and not 9999.
Is there a way to write this code that will solve the above issues?

Another issue reported by Klocwork is 'port' is used uninitialized in this function. It specifically mentions that passing '&port' to 'po::value'
This is a false positive: nothing uses the value of port before it's initialized (I checked). However, it should be enough to actually initializing port to silence the message, by. It's weird that it still triggers, since you already had that.
Neither vaglrind nor ASAN+UBSAN find anything wrong with the code for me. Here's a brute force test that tries all kinds of option combinations (including unregistered and erroneous):
#!/bin/bash
set -e -u
opts=( '' '-k two' '-k 2' '-p 2345' '-s 127.0.0.88' 'bogus' '--more-bogus');
for a in "${opts[#]}"
do
for b in "${opts[#]}"
do
for c in "${opts[#]}"
do
valgrind ./sotest "$a" "$b" "$c"
done
done
done
That ends up running 343 different invocations of the program and ends up printing the expected outputs:
69x 2
69x 2345
69x 127.0.0.88
99x 1
99x 1234
99x localhost
The expected diagnostics:
17x option '--port' cannot be specified more than once
17x option '--server_ip' cannot be specified more than once
34x option '--party' cannot be specified more than once
107x the argument ('two') for option '--party' is invalid
And most importantly, consistent leak-free report:
343 All heap blocks were freed -- no leaks are possible
TL;DR
I don't know why your tooling reports leaks. At the very least, the "'port' is used uninitialized" issue seems wrong on close inspection.
I tested on GCC 10 with Boost 1.73.0, -std=c++17 -O3, your source 1--% unaltered.
I hope this gives you more ideas and perhaps some reassurance.

Related

How to store data in boost::program_options::variable_map?

I am currently trying to rework some code that was handed down to me. The original point of the code is to read a configuration file, and to set up the different options in the file in a boost::program_options::variable_map, which is then read throughout other parts of the code which is already working fine.
Here is the code I am trying to replace:
// Some helpful definitions
boost::program_options::variables_map vm;
std::string filecfg = "File_name";
std::ifstream ifs(filecfg.c_str());
// Setting options (This is command line example, but config file is the same)
boost::program_options::options_description df("Command Line");
df.add_options()
("help", "display help message")
("file-cfg,f", boost::program_options::value<std::string>(), "config file")
("version", "display version and revision number");
boost::program_options::parsed_options parsedc = boost::program_options::parse_config_file(ifs, df, true);
boost::program_options::store(parsedc, vm);
boost::program_options::notify(vm);
std::vector <std::string> unrc = boost::program_options::collect_unrecognized(parsedc.options, boost::program_options::include_positional)
My thinking it to simply replace the boost::program_options::parsed_options parsedc and create this object by myself. The problem I run into is simply that there is no documentation on how to do this. I think it is mostly because it is not designed to be used this way.
In any case, I am just looking to fill up the vm object with the options described in dc, and with values that I can hold in a separate data structure (like a vector).
Is it possible to simply add values to vm? Or do I have to go through a function such as boost::program_options::store()?
Any help would be greatly appreciated! Let me know if something is unclear, or if there is something you'd like me to try!
Thanks!
Yeah you can.
Be aware that you will have to decide how to "mock"/"fake" the other semantics of it though. (E.g. you might want to masquerade the options as having been defaulted)
Conceptually, variable_map would be a map<string, variable_value>. variable_value:
Class holding value of option. Contains details about how the value is
set and allows to conveniently obtain the value.
Note also that because variable_value uses boost::any for storage you will have to be exact about the types you will store. (So, don't store "oops" if you need a std::string("ah okay")).
Here's a simple demo:
Live On Coliru
#include <boost/program_options.hpp>
#include <iostream>
#include <iomanip>
namespace po = boost::program_options;
using namespace std::string_literals;
int main(/*int argc, char** argv*/) {
// Some helpful definitions
po::variables_map vm;
vm.emplace("file-cfg", po::variable_value("string"s, true));
vm.emplace("log-level", po::variable_value(3, false));
vm.emplace("option3", po::variable_value{});
notify(vm);
std::vector unrc = { "unrecognized"s, "options"s };
for (auto& [name, value] : vm) {
std::cout
<< "Name: " << name
<< std::boolalpha
<< "\tdefaulted:" << value.defaulted()
<< "\tempty:" << value.empty();
if (typeid(std::string) == value.value().type())
std::cout << " - string " << std::quoted(value.as<std::string>()) << "\n";
else if (typeid(int) == value.value().type())
std::cout << " - int " << value.as<int>() << "\n";
else if (!value.empty())
std::cout << " - unknown type\n";
}
}
Prints
Name: file-cfg defaulted:true empty:false - string "string"
Name: log-level defaulted:false empty:false - int 3
Name: option3 defaulted:false empty:true
I warn you not to use vm.emplace(…, po::variable_value(…,…)).
It's quite deceptive: it will work to some extent but fail spectacularly elsewhere.
When you use po::store, it internally also produces a po::variable_value and copies the semantic of your option to a private field of the po::variable_value. There's no way to set this semantic yourself. (see: https://github.com/boostorg/program_options/blob/develop/src/variables_map.cpp#L83).
Without the semantic you can't at least:
read the option from multiple sources
vm.notify() will not write the value to variables associated with the option
Here's an (arguably ugly) way that should avoid these issues:
po::variables_map vm;
po::options_description opts;
opts.add_options()("optName", …);
…
po::parsed_options parsedOpts(&opts);
pOpts.options.push_back(po::option("optName", {"optValue"}));
po::store(parsedOpts, vm);
First, one has to create a parsedOpts object that stores the description of options. Then, add an option name and list of values as strings, regardless of the option type. Finally, within po::store, the name and value(s) are parsed and stored in vm.
A complete working example:
#include <boost/program_options.hpp>
#include <iostream>
namespace po = boost::program_options;
int main(int ac, char **av) {
int i = 0;
po::variables_map vm;
po::options_description opts;
opts.add_options()("id", po::value<int>(&i)->default_value(1));
int userInput;
std::cin >> userInput;
if (userInput == 2) {
vm.emplace("id", po::variable_value(userInput, false));
}
if (userInput == 3) {
po::parsed_options pOpts(&opts);
pOpts.options.push_back(po::option("id", {std::to_string(userInput)}));
po::store(pOpts, vm);
}
po::store(po::parse_command_line(ac, av, opts), vm);
//po::store(po::parse_config_file("options.ini", opts, true), vm);
po::notify(vm);
std::cout << "id (notified): " << i << std::endl;
std::cout << "id (from vm): " << vm["id"].as<int>() << std::endl;
return 0;
}
Typing 2 runs vm.emplace and yields:
id (notified): 0
id (from vm): 2
which is bad, for po::value<int>(&i) was ignored
Typing 2 and adding --id=4 command line argument yields:
terminate called after throwing an instance of 'boost::wrapexcept<boost::program_options::multiple_occurrences>'
which is bad, for you cannot use multiple sources
Typing 3 runs the po::store on hand-crafted po::parsed_options and yields:
id (notified): 3
id (from vm): 3
Typing 3 and adding --id=4 command line argument yields:
id (notified): 3
id (from vm): 3
Which is correct & expected, for the subsequent stores shall not replace values that were stored earlier (see https://www.boost.org/doc/libs/1_80_0/doc/html/program_options/tutorial.html#id-1.3.30.4.5)

boost program options count number of occurrences of a flag

I am trying to program in a way for the user of my program to specify the level of verbosity of my program from 0 to 3. I was told by someone that there might be a way to set up the program options so that I am able to detect the number of occurrences of a flag, and then run my program accordingly.
Example:
[none] -> level 0
-v -> level 1
-vv -> level 2
-vvv -> level 3
Does anyone know if this is possible? Do I just need to set up three different options, one for each possibility? I have tried to search around for a similar example however I fear I may be searching the wrong things.
I can't think of a nice way. boost::program_options option syntax is a little more structured (and arguably more simplistic) than getopt.
Here's one way:
#include <boost/program_options.hpp>
#include <iostream>
#include <algorithm>
#include <cstdlib>
int main(int argc, char**argv)
{
namespace po = boost::program_options;
std::string verbosity_values;
po::options_description desc("Command Line Options");
desc.add_options()("verbosity,v",
po::value(&verbosity_values)->implicit_value(""),
"verbose");
po::variables_map vm;
po::store(po::parse_command_line(argc, argv, desc), vm);
po::notify(vm);
if (vm.count("verbosity")) {
verbosity_values += "v";
}
if (std::any_of(begin(verbosity_values), end(verbosity_values), [](auto&c) { return c != 'v'; })) {
std::cerr << "invalid verbosity" << std::endl;
std::exit(100);
}
std::cout << "verbosity: " << verbosity_values.size() << std::endl;
}
How it works:
define an option called "--verbosity" with a synonym "-v".
'verbosity' takes a string argument, which we default to ""
we check that the string contains only 'v's
if the variables_map contains a 'verbosity' argument, then -v or --verbosity must have been mentioned on the command line. Therefore, add a 'v' to the string.
verbosity is the length of the string.
example:
$ ./a.out -vvvv
verbosity: 4
$

How to disable cout output in the runtime?

I often use cout for debugging purpose in many different places in my code, and then I get frustrated and comment all of them manually.
Is there a way to suppress cout output in the runtime?
And more importantly, let's say I want to suppress all cout outputs, but I still want to see 1 specific output (let's say the final output of the program) in the terminal.
Is it possible to use an ""other way"" of printing to the terminal for showing the program output, and then when suppressing cout still see things that are printed using this ""other way""?
Sure, you can (example here):
int main() {
std::cout << "First message" << std::endl;
std::cout.setstate(std::ios_base::failbit);
std::cout << "Second message" << std::endl;
std::cout.clear();
std::cout << "Last message" << std::endl;
return 0;
}
Outputs:
First message
Last message
This is because putting the stream in fail state will make it silently discard any output, until the failbit is cleared.
To supress output, you can disconnect the underlying buffer from cout.
#include <iostream>
using namespace std;
int main(){
// get underlying buffer
streambuf* orig_buf = cout.rdbuf();
// set null
cout.rdbuf(NULL);
cout << "this will not be displayed." << endl;
// restore buffer
cout.rdbuf(orig_buf);
cout << "this will be dispalyed." << endl;
return 0;
}
Don't use cout for debugging purposes, but define a different object (or function, or macro) that calls through to it, then you can disable that function or macro in one single place.
You can user cerr - standard output stream for errors for your debug purposes.
Also, there is clog - standard output stream for logging.
Typically, they both behave like a cout.
Example:
cerr << 74 << endl;
Details: http://www.cplusplus.com/reference/iostream/cerr/
http://www.cplusplus.com/reference/iostream/clog/
If you include files which involve cout you may want to write the code at the start (outside of main), which can be done like this:
struct Clearer {
Clearer() { std::cout.setstate(std::ios::failbit); }
} output_clearer;
It seems you print debug messages. You could use TRACE within Visual C++/MFC or you just might want to create a Debug() function which takes care of it. You can implement it to turn on only if a distinct flag is set. A lot of programs use a command line parameter called verbose or -v for instance, to control the behavior of their log and debug messages.

gnu slist execute error: lost of file .../bits/allocator.h: No such file

I'm using Ubuntu. g++ version 4.7.2.
Can anyone help me with the gnu-extension single list? I compiled the stuff here and got a core dump when executed.
I debuged it and saw the core dump happend in the first line, where it throwed an error that I cannot solve. May anyone please help me with that??
the error code:
std::allocator<char>::allocator (this=0x7fffffffe4d0)
at /build/buildd/gcc-4.7-4.7.2/build/x86_64-linux-gnu/libstdc++-v3/include/bits/allocator.h:104
104 /build/buildd/gcc-4.7-4.7.2/build/x86_64-linux-gnu/libstdc++-v3/include/bits/allocator.h: No such file or directory.
This is my test code:
#include <ext/slist>
#include <cstring>
#include <iostream>
int main(int argc, char * argv[])
{
__gnu_cxx::slist<char> li(&argv[1][0], &(argv[1][strlen(argv[1])]));
if(argc != 3)
return 1;
std::cout << "SList: ";
for(__gnu_cxx::slist<char>::iterator i = li.begin();
i != li.end();
++i)
std::cout << *i;
std::cout << std::endl;
li.remove(argv[2][0]);
for(__gnu_cxx::slist<char>::iterator i = li.begin();
i != li.end();
++i)
std::cout << *i;
std::cout << std::endl;
return 0;
}//main
My guess is that you're not giving any command-line arguments when you run it. It expects two: the character sequence to put in the list, and the character sequence to remove.
UPDATE: as mentioned in the comments, to pass the arguments to your program when using gdb, you need to use the --args option to indicate that arguments following the program name should be passed to the program, not to gdb itself:
gdb --args a.out xxyyxx x
^^^^^^
It initialises the list from the first argument argv[1] before checking that that argument exists; if it doesn't, then you'll get undefined behaviour. If you move the check above the declaration of li, then the program should exit with return code 1 instead in that case.
Then the debugger complains that it can't find the source file, and so can't show you on which source line it went wrong.
By the way, the C++ standard library now includes a singly-linked list, std::forward_list, defined in <forward_list>, which you could use instead of GNU's extension.

How do I get default argument values with boost program options?

I want to use default values for some of my command line arguments. How do I tell program_options what the default option is, and, if the user doesn't supply the argument, how do I tell my program to use the default value?
Say I want to have an argument specifying the number of robots to send on a murderous rampage with a default value of 3.
robotkill --robots 5 would produce 5 robots have begun the silicon revolution, whereas
robotkill (no arguments supplied) would produce 3 robots have begun the silicon revolution.
program_options automatically assigns default values to options when the user doesn't supply those options. You don't even need to check whether the user supplied a given option, just use the same assignment in either case.
#include <iostream>
#include <boost/program_options.hpp>
namespace po = boost::program_options;
int main (int argc, char* argv[]) {
po::options_description desc("Usage");
desc.add_options()
("robots", po::value<int>()->default_value(3),
"How many robots do you want to send on a murderous rampage?");
po::variables_map opts;
po::store(po::parse_command_line(argc, argv, desc), opts);
try {
po::notify(opts);
} catch (std::exception& e) {
std::cerr << "Error: " << e.what() << "\n";
return 1;
}
int nRobots = opts["robots"].as<int>();
// automatically assigns default when option not supplied by user!!
std::cout << nRobots << " robots have begun the silicon revolution"
<< std::endl;
return 0;
}