Adding a new checker to the clang static analyzer – Debugging Using LLVM Tools-4

  1. If the symbol is dead, then we need to check the state. If the state is still open, then this is a potential resource leak. There is one exception: iconv_open() returns -1 in case of an error. If the analyzer is in a code path that handles this error, then it is wrong to assume a resource leak because the function call failed. We try to get the value of the symbol from the ConstraintManager instance, and we do not consider the symbol as a resource leak if this value is -1. We add a leaked symbol to a SmallVector instance to generate the error report later. Finally, we remove the dead symbol from the program state:
    if (St.isOpen()) {
    bool IsLeaked = true;
    if (const llvm::APSInt *Val =
    State->getConstraintManager().getSymVal(
    State, Sym))
    IsLeaked = Val->getExtValue() != -1;
    if (IsLeaked)
    LeakedSyms.push_back(Sym);
    }
    State = State->remove(Sym);
    }
    }
  1. After the loop, we call the generateNonFatalErrorNode() method. This method transitions to the new program state and returns an error node if there is not already an error node for this path. The LeakedSyms container holds the (possibly empty) list of leaked symbols, and we call the report() method to generate an error report:
    if (ExplodedNode *N =
    C.generateNonFatalErrorNode(State)) {
    report(LeakedSyms, *LeakBugType,
    “Opened iconv descriptor not closed”, C, N);
    }
    }
  1. The checkPointerEscape() function is called when the analyzer detects a function call for which the parameters cannot be tracked. In such a case, we must assume that we do not know if the iconv descriptor will be closed inside the function or not. The exceptions are a call to iconv(), which does the conversion and is known to not call the iconv_close() function, and the iconv_close() function itself, which we handle in the checkPreCall() method. We also do not change the state if the call is inside a system header file, and if we know that the arguments do not escape in the called function. In all other cases, we remove the symbol from the state:
    ProgramStateRef IconvChecker::checkPointerEscape(
    ProgramStateRef State,
    const InvalidatedSymbols &Escaped,
    const CallEvent Call, PointerEscapeKind Kind) const { if (Kind == PSK_DirectEscapeOnCall) { if (IconvFn.matches(Call) ||
    IconvCloseFn.matches(*Call))
    return State;
    if (Call->isInSystemHeader() ||
    !Call->argumentsMayEscape())
    return State;
    }
    for (SymbolRef Sym : Escaped)
    State = State->remove(Sym);
    return State;
    }
  1. The report() method generates an error report. The important parameters of the method are an array of symbols, the type of the bug, and a bug description. Inside the method, a bug report is created for each symbol, and the symbol is marked as the interesting one for the bug. If a source range is provided as a parameter, then this is also added to the report. Finally, the report is emitted:
    void IconvChecker::report(
    ArrayRef Syms, const BugType &Bug,
    StringRef Desc, CheckerContext &C,
    ExplodedNode ErrNode, std::optional Range) const { for (SymbolRef Sym : Syms) { auto R = std::make_unique( Bug, Desc, ErrNode); R->markInteresting(Sym); if (Range) R->addRange(Range);
    C.emitReport(std::move(R));
    }
    }
  1. Now, the new checker needs to be registered at a CheckerRegistry instance. When our plugin is loaded, the clang_registerCheckers() function is used, in which we perform the registration. Each checker has a name and belongs to a package. We call the IconvChecker checker and put it into the unix packager because the iconv library is a standard POSIX interface. This is the first parameter of the addChecker() method. The second parameter is a brief documentation of the functionality, and the third parameter can be a URI to a document that provides more information about the checker:
    extern “C” void
    clang_registerCheckers(CheckerRegistry &registry) {
    registry.addChecker(
    “unix.IconvChecker”,
    “Check handling of iconv functions”, “”);
    }

Leave a Reply

Your email address will not be published. Required fields are marked *