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
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.