boost::program_options 在 Klocwork 中生成 MLK.MUST

boost::program_options generating MLK.MUST in Klocwork

我基于 Boost 库编写了以下 C++ 代码以从命令行获取输入。

#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;
}

它按预期工作。但是,Klocwork 报了如下错误(我已经调整了这段代码的行号):

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'

我找到了这个旧的 post boost program_options generating a Klocwork MLK.MUST。但是看了答案,还是不知道怎么解决这个问题。

Klocwork 报告的另一个问题是 'port' is used uninitialized in this function。它特别提到 passing '&port' to 'po::value<int>' does not initialize 'port'。但是,在 运行 代码之后,我看到它确实初始化了端口,因为端口值打印为 1234 而不是 9999。

有没有办法编写可以解决上述问题的代码?

Another issue reported by Klocwork is 'port' is used uninitialized in this function. It specifically mentions that passing '&port' to 'po::value'

这是误报:port 在初始化之前没有使用它的值(我检查过)。但是,实际初始化 port 以使消息静音应该就足够了。奇怪的是它仍然会触发,因为你已经拥有了。

vaglrind 和 ASAN+UBSAN 都没有发现我的代码有任何问题。这是一个尝试各种选项组合(包括未注册和错误的)的蛮力测试:

#!/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

最终 运行 程序的 343 次不同调用最终打印出预期的输出:

 69x 2
 69x 2345
 69x 127.0.0.88

 99x 1
 99x 1234
 99x localhost

预期的诊断:

 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

最重要的是,一致的 leak-free 报告:

343 All heap blocks were freed -- no leaks are possible

TL;DR

我不知道为什么您的工具报告泄漏。至少,"'port' used uninitialized" 问题在仔细检查时似乎是错误的。

我使用 Boost 1.73.0 在 GCC 10 上进行了测试,-std=c++17 -O3,您的源代码 1--% 未更改。

我希望这能给你更多的想法,或许还能给你一些安慰。