Parasoft C++test中令人困惑的控制流分析

8
我们使用Parasoft C++test来静态分析我们的代码。它在处理以下代码时出现了问题:
void foo(int* x) {
    try {
        bar();
    } catch(...) {
        delete x;
        throw;
    }

    *x;
}

它在*x;行发出警告:

任何情况下都不应访问已释放的内存

一些方法得出结论,控制流可以进入catch(...)块,删除x,绕过throw;,并到达*x;。我尝试了throw std::exception("");和其他几个方法,结果都是一样的。Parasoft肯定知道异常并将其纳入其控制流中,因为有许多其他测试涉及异常检查。它只是在这种情况下感到困惑,还是实际上有一种方式可以使该程序的执行同时触发delete x;*x;


我觉得它似乎有些混淆了。 - Jerry Coffin
@unapersson 这只是一个演示问题的片段。 - Michael Mrozek
1
你可以尝试在 throw 之后添加一个 abort()。但谁知道,也许会被诊断为死代码... - Peter G.
2
它可能会检查bar(); 如果已知bar()会释放x(或者在进入foo之前静态地知道x将被释放),那么这不会有错。在所有其他情况下,流分析会变得混乱 :) - sehe
@sehe bar()实际上是空的,删除调用不会改变分析结果(我只包含它是为了尝试避免它检测到catch永远不会发生,但我猜它不检查) - Michael Mrozek
显示剩余6条评论
3个回答

2

所以这个工具是错的(我知道之前已经说过),我假设您不想关闭警告。

我同意@Pascal的评论,为了解决某个工具的限制而重写代码有点危险。你可以禁用当前存在问题的文件中的警告。

然后,你就有了一个无警告的构建起点,没有工具告诉你要重写现有有效的代码。

对于新代码,您将需要采用一些工具理解的风格。这不是太大的问题,因为那将是您目前正在使用的代码,所以如果需要稍微重写一下以摆脱警告,那也不是太大的问题。

虽然正确,但现有的代码风格远非理想。

我建议像x这样的指针存储在auto_ptr中。如果auto_ptr超出作用域,则它将自动删除auto_ptr的内容-除非您显式地将其从auto_ptr中取出。这对眼睛来说更容易,也很好地说明了该函数拥有指针所有权。

void foo(auto_ptr<int> x)
{
    bar();
    *x;
}

我认为ParaSoft不会对这段代码有任何问题。

0
也许这是一个愚蠢的建议,但如果您将catch留到最后,Parasoft会有什么反应呢?即:
void foo(int* x) 
  {
  try 
    {
    bar();
    *x;
    } 
  catch(...) 
    {
    delete x;
    throw;
    }      
  }

我意识到这种方法可能并不适用于所有语句和异常的组合,例如如果您有多个异常类型需要在foo的不同阶段进行不同的处理,但至少它可以为您提供一个解决警告的起点,如果您真的想要摆脱这个警告。


1
如果它能解决问题,那么它并不是无关紧要的 - 尽管我倾向于忽略Parasoft分析工具明显错误的结论。 - Joris Timmermans
我赞同这个评论。如果你开始通过改变代码来避免假警报,你会引入错误。这可能是50次中的一次,也可能是200次中的一次。无论如何,你都会花费时间引入错误。 - Pascal Cuoq

0
快速更新:
1)上述提到的规则根本不是一个流分析规则。也就是说,这个规则(ID MRM-31)在C++test 9.2.0及之后的版本中得到了改进。C++test中还有一个相应的流分析规则(ID:BD-RES-FREE),它应该能满足您的需求。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接