Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/128.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/codeigniter/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ Clang静态分析器检查函数是否被调用两次_C++_Clang_Clang Static Analyzer - Fatal编程技术网

C++ Clang静态分析器检查函数是否被调用两次

C++ Clang静态分析器检查函数是否被调用两次,c++,clang,clang-static-analyzer,C++,Clang,Clang Static Analyzer,我有一个新的自定义检查器(TransactionChecker.cpp) 以下是交易状态: struct TransactionState { private: enum Kind { OpenedT, StartedT, FinalizedT, ClosedT } K; TransactionState(Kind InK) : K(InK) {} public: bool isOpened() const { return K == OpenedT; } bool isClo

我有一个新的自定义检查器(TransactionChecker.cpp)

以下是交易状态:

struct TransactionState {
private:
  enum Kind { OpenedT, StartedT, FinalizedT, ClosedT } K;
  TransactionState(Kind InK) : K(InK) {}

public:
  bool isOpened() const { return K == OpenedT; }
  bool isClosed() const { return K == ClosedT; }
  bool isStarted() const { return K == StartedT; }
  bool isFinalized() const { return K == FinalizedT; }

  static TransactionState getOpened() { return TransactionState(OpenedT); }
  static TransactionState getClosed() { return TransactionState(ClosedT); }
  static TransactionState getStarted() { return TransactionState(StartedT); }
  static TransactionState getFinalized() {
    return TransactionState(FinalizedT);
  }

  bool operator==(const TransactionState &X) const { return K == X.K; }
  void Profile(llvm::FoldingSetNodeID &ID) const { ID.AddInteger(K); }
};
我的头文件和test.c

void checkDoubleOpen(){
  TRANSACTION *T = open_transaction();
  T = open_transaction();  // expected-warning {{Open a previously open transaction}}


#pragma clang system_header


typedef struct __sTRANSACTION {
  unsigned char *_p;
  int value;
} TRANSACTION;

void startTransaction(TRANSACTION *T,int val);
int finalizeTransaction(TRANSACTION *T);
TRANSACTION* open_transaction();
int close_transaction(TRANSACTION*);

void fakeSystemHeaderCall(TRANSACTION *);
运行后:

clang -cc1 -analyze -analyzer-checker=alpha.unix.Transaction test.c
我想打印那个警告

我用
注册了\u MAP\u程序状态(MAPSymbolTS,SymbolRef,TransactionState)

void TransactionChecker::checkPostCall(const CallEvent&Call,
CheckerContext&C)常量{
如果(!Call.isGlobalFunction())
返回;
如果(!Call.isCalled(OpenTran))
返回;
ProgramStateRef State=C.getState();
//获取与文件句柄对应的符号值。
FunctionDecl FileDesc=Call.getReturnValue().getAsSymbol();
如果(!FileDesc)
返回;
const struct TransactionState*TState=State->get(FileDesc);
如果(!TState){
//生成下一个过渡(分解图中的边)。
State=State->set(FileDesc,TransactionState::getOpened());
C.过渡(国家);
}否则{
reportOpenAfterOpen(Call,C);
}
}
但是没有成功

我想我需要一个新的映射:key=unknown(函数名+id配置文件)和value-TransactionState,但不知道如何创建它

问题的解释 只要有一个路径调用了两次
open\u transaction
,而没有中间的
close\u transaction
,您就要进行报告

概述 正如在评论中提到的,这有点像教程检查器。但是,该检查器正在跟踪多个对象的状态,而在这里,该状态是程序的全局状态。这使它更类似于,所以我们将模仿它

虽然教程检查器使用贴图,但这里我们只需要跟踪单个值。我将使用一个
无符号
计数器:

REGISTER\u TRAIT\u WITH\u programmastate(称为wicecounter,无符号)
当我们看到调用
open\u transaction
时,增加计数器:

if(FD->getIdentifier()==II_打开){
//更新抽象状态以反映调用的数量。
无符号计数器=状态->获取();
计数器++;
状态=状态->设置(计数器);
C.过渡(国家);
如果计数器超过2,则报告缺陷

类似地,当我们看到
close\u事务时,将其递减

完整示例 调用wicechecker.cpp:

//调用了wicechecker.cpp
// https://stackoverflow.com/questions/48241792/clang-static-analyzer-check-if-a-function-was-called-twice
#包括“clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h”
#包括“clang/StaticAnalyzer/Core/BugReporter/BugType.h”
#包括“clang/StaticAnalyzer/Core/Checker.h”
#包括“clang/StaticAnalyzer/Core/CheckerManager.h”
#包括“clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h”
#包括“clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h”
#包括“clang/StaticAnalyzer/Core/PathSensitive/programstatetracit.h”
使用名称空间铿锵;
使用名称空间ento;
名称空间{
类CalledTwiceChecker:PublicChecker{
可变标识信息*II_打开,*II_关闭;
可变std::称为WICE的唯一ptr BT;
公众:
被称为wicechecker()
:II_open(nullptr),II_close(nullptr){}
bool evalCall(const CallExpr*CE、CheckerContext&C)const;
};
}//结束匿名命名空间
//在上调用感兴趣函数的次数
//当前路径。自动初始化为零。
//
//基于BlockInCriticalSectionChecker.cpp中的类似代码。
将\u TRAIT\u注册到\u PROGRAMSTATE(称为wiceCounter,无符号)
bool CalledTwiceChecker::evalCall(constcallexpr*CE、CheckerContext&C)const{
const FunctionDecl*FD=C.getCalleeDecl(CE);
如果(!FD | | FD->getKind()!=Decl::Function){
返回false;
}
ASTContext&Ctx=C.getASTContext();
如果(!II_打开){
II_open=&Ctx.Idents.get(“open_事务”);
}
如果(!II_关闭){
II_close=&Ctx.Idents.get(“close_事务”);
}
ProgramStateRef state=C.getState();
如果(FD->getIdentifier()==II_打开){
//更新抽象状态以反映调用的数量。
无符号计数器=状态->获取();
计数器++;
状态=状态->设置(计数器);
C.过渡(国家);
//llvm::errs()getIdentifier()==II_close){
无符号计数器=状态->获取();
如果(计数器>0){
计数器--;
状态=状态->设置(计数器);
C.过渡(国家);
返回true;
}
否则{
返回false;
}
}
返回false;
}
void ento::registerCalledTwiceChecker(检查管理器和经理){
注册检查经理();
}
bool ento::应该注册调用wicechecker(const LangOptions&LO){
返回true;
}
要将其与Clang的其余部分挂钩,请将条目添加到:

  • clang/include/clang/StaticAnalyzer/Checkers/Checkers.td
  • clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt
测试它的输入示例:

//calltweeps.c
//测试被调用的wicechecker。
作废未结交易();
作废关闭交易();
void open_once()
{
打开_事务();//未报告
}
作废打开_两次()
{
打开_事务();
打开_事务();//已报告
}
无效打开每个路径一个路径(int x)
{
if(x){
打开_事务();
}
否则{
打开_事务();//未报告
}
}
作废打开\关闭\打开()
{
打开_事务();
关闭_事务();
打开_事务();//未报告
}
作废打开\关闭\打开\打开()
{
打开_事务();
关闭_事务();
打开_事务();
打开_事务();//已报告
}
int某物();
无效开环()
{
while(某物()){
打开_事务();//已报告
}
}
对该输入运行分析:

$gcc-E-o calltweep.i calltweep.c
$~/bld/llvm project/build/bin/clang-cc1-analyze-analyzer checker=alpha.core.CalledTwice calltweeth.i
调用两次。c:15:3:警告:打开\u事务调用两次
打开_事务();
^~~~~~~~~~~~~~~~~~
calltwic
void TransactionChecker::checkPostCall(const CallEvent &Call,
                                       CheckerContext &C) const {
  if (!Call.isGlobalCFunction())
    return;

  if (!Call.isCalled(OpenTran))
    return;

  ProgramStateRef State = C.getState();

  // Get the symbolic value corresponding to the file handle.
  FunctionDecl FileDesc = Call.getReturnValue().getAsSymbol();

  if (!FileDesc)
       return;

 const struct TransactionState *TState = State->get<MAPSymbolTS>(FileDesc);
  if (!TState) {
    // Generate the next transition (an edge in the exploded graph).
    State = State->set<MAPSymbolTS>(FileDesc, TransactionState::getOpened());
    C.addTransition(State);
  } else {
    reportOpenAfterOpen(Call, C);
  }
}