#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
using namespace clang;
using namespace ento;
namespace {
class StringChecker : public Checker<check::PreCall> {
BugType BT_Null{this, "Dereference of null pointer", categories::LogicError};
mutable const FunctionDecl *StringConstCharPtrCtor = nullptr;
mutable CanQualType SizeTypeTy;
const CallDescription TwoParamStdStringCtor = {
CDM::CXXMethod, {"std", "basic_string", "basic_string"}, 2, 2};
bool isCharToStringCtor(const CallEvent &Call, const ASTContext &ACtx) const;
public:
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
};
bool StringChecker::isCharToStringCtor(const CallEvent &Call,
const ASTContext &ACtx) const {
if (!TwoParamStdStringCtor.matches(Call))
return false;
const auto *FD = dyn_cast<FunctionDecl>(Call.getDecl());
assert(FD);
if (StringConstCharPtrCtor && StringConstCharPtrCtor == FD)
return true;
const QualType Arg1Ty = Call.getArgExpr(0)->getType().getCanonicalType();
const QualType Arg2Ty = Call.getArgExpr(1)->getType().getCanonicalType();
if (!Arg1Ty->isPointerType())
return false;
if (Arg2Ty.getCanonicalType() == ACtx.getSizeType())
return false;
StringConstCharPtrCtor = FD;
return true;
}
void StringChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
if (!isCharToStringCtor(Call, C.getASTContext()))
return;
const auto Param = Call.getArgSVal(0).getAs<Loc>();
if (!Param)
return;
ProgramStateRef NotNull, Null;
std::tie(NotNull, Null) = C.getState()->assume(*Param);
if (NotNull) {
const auto Callback = [Param](PathSensitiveBugReport &BR) -> std::string {
return BR.isInteresting(*Param) ? "Assuming the pointer is not null."
: "";
};
C.addTransition(NotNull, Null ? C.getNoteTag(Callback) : nullptr);
return;
}
if (ExplodedNode *N = C.generateErrorNode(C.getState())) {
auto R = std::make_unique<PathSensitiveBugReport>(
BT_Null, "The parameter must not be null", N);
bugreporter::trackExpressionValue(N, Call.getArgExpr(0), *R);
C.emitReport(std::move(R));
}
}
}
void ento::registerStringChecker(CheckerManager &Mgr) {
Mgr.registerChecker<StringChecker>();
}
bool ento::shouldRegisterStringChecker(const CheckerManager &) { return true; }