151fb8b01SRoman Divacky //===--- UndefinedAssignmentChecker.h ---------------------------*- C++ -*--==//
251fb8b01SRoman Divacky //
322989816SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
422989816SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
522989816SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
651fb8b01SRoman Divacky //
751fb8b01SRoman Divacky //===----------------------------------------------------------------------===//
851fb8b01SRoman Divacky //
901af97d3SDimitry Andric // This defines UndefinedAssignmentChecker, a builtin check in ExprEngine that
1051fb8b01SRoman Divacky // checks for assigning undefined values.
1151fb8b01SRoman Divacky //
1251fb8b01SRoman Divacky //===----------------------------------------------------------------------===//
1351fb8b01SRoman Divacky
14676fbe81SDimitry Andric #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
15809500fcSDimitry Andric #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
1601af97d3SDimitry Andric #include "clang/StaticAnalyzer/Core/Checker.h"
1701af97d3SDimitry Andric #include "clang/StaticAnalyzer/Core/CheckerManager.h"
1801af97d3SDimitry Andric #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
1951fb8b01SRoman Divacky
2051fb8b01SRoman Divacky using namespace clang;
21bca07a45SDimitry Andric using namespace ento;
2251fb8b01SRoman Divacky
231569ce68SRoman Divacky namespace {
241569ce68SRoman Divacky class UndefinedAssignmentChecker
2501af97d3SDimitry Andric : public Checker<check::Bind> {
2677dbea07SDimitry Andric const BugType BT{this, "Assigned value is garbage or undefined"};
2701af97d3SDimitry Andric
281569ce68SRoman Divacky public:
2936981b17SDimitry Andric void checkBind(SVal location, SVal val, const Stmt *S,
3036981b17SDimitry Andric CheckerContext &C) const;
311569ce68SRoman Divacky };
321569ce68SRoman Divacky }
331569ce68SRoman Divacky
checkBind(SVal location,SVal val,const Stmt * StoreE,CheckerContext & C) const3401af97d3SDimitry Andric void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
3536981b17SDimitry Andric const Stmt *StoreE,
3601af97d3SDimitry Andric CheckerContext &C) const {
3751fb8b01SRoman Divacky if (!val.isUndef())
3851fb8b01SRoman Divacky return;
3951fb8b01SRoman Divacky
40bfef3995SDimitry Andric // Do not report assignments of uninitialized values inside swap functions.
41bfef3995SDimitry Andric // This should allow to swap partially uninitialized structs
42bfef3995SDimitry Andric if (const FunctionDecl *EnclosingFunctionDecl =
43bfef3995SDimitry Andric dyn_cast<FunctionDecl>(C.getStackFrame()->getDecl()))
44bfef3995SDimitry Andric if (C.getCalleeName(EnclosingFunctionDecl) == "swap")
45bfef3995SDimitry Andric return;
46bfef3995SDimitry Andric
4745b53394SDimitry Andric ExplodedNode *N = C.generateErrorNode();
4851fb8b01SRoman Divacky
4951fb8b01SRoman Divacky if (!N)
5051fb8b01SRoman Divacky return;
5151fb8b01SRoman Divacky
5251fb8b01SRoman Divacky // Generate a report for this bug.
5348675466SDimitry Andric llvm::SmallString<128> Str;
5448675466SDimitry Andric llvm::raw_svector_ostream OS(Str);
5548675466SDimitry Andric
569f4dbff6SDimitry Andric const Expr *ex = nullptr;
5751fb8b01SRoman Divacky
583d1dcd9bSDimitry Andric while (StoreE) {
59461a67faSDimitry Andric if (const UnaryOperator *U = dyn_cast<UnaryOperator>(StoreE)) {
6048675466SDimitry Andric OS << "The expression is an uninitialized value. "
61461a67faSDimitry Andric "The computed value will also be garbage";
62461a67faSDimitry Andric
63461a67faSDimitry Andric ex = U->getSubExpr();
64461a67faSDimitry Andric break;
65461a67faSDimitry Andric }
66461a67faSDimitry Andric
673d1dcd9bSDimitry Andric if (const BinaryOperator *B = dyn_cast<BinaryOperator>(StoreE)) {
6811d2b2d2SRoman Divacky if (B->isCompoundAssignmentOp()) {
6948675466SDimitry Andric if (C.getSVal(B->getLHS()).isUndef()) {
7048675466SDimitry Andric OS << "The left expression of the compound assignment is an "
7111d2b2d2SRoman Divacky "uninitialized value. The computed value will also be garbage";
7211d2b2d2SRoman Divacky ex = B->getLHS();
7311d2b2d2SRoman Divacky break;
7411d2b2d2SRoman Divacky }
7511d2b2d2SRoman Divacky }
7611d2b2d2SRoman Divacky
7751fb8b01SRoman Divacky ex = B->getRHS();
7811d2b2d2SRoman Divacky break;
7911d2b2d2SRoman Divacky }
8011d2b2d2SRoman Divacky
813d1dcd9bSDimitry Andric if (const DeclStmt *DS = dyn_cast<DeclStmt>(StoreE)) {
82519fc96cSDimitry Andric const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
8351fb8b01SRoman Divacky ex = VD->getInit();
8451fb8b01SRoman Divacky }
8511d2b2d2SRoman Divacky
8648675466SDimitry Andric if (const auto *CD =
8748675466SDimitry Andric dyn_cast<CXXConstructorDecl>(C.getStackFrame()->getDecl())) {
8848675466SDimitry Andric if (CD->isImplicit()) {
89e3b55780SDimitry Andric for (auto *I : CD->inits()) {
9048675466SDimitry Andric if (I->getInit()->IgnoreImpCasts() == StoreE) {
9148675466SDimitry Andric OS << "Value assigned to field '" << I->getMember()->getName()
9248675466SDimitry Andric << "' in implicit constructor is garbage or undefined";
9348675466SDimitry Andric break;
9448675466SDimitry Andric }
9548675466SDimitry Andric }
9648675466SDimitry Andric }
9748675466SDimitry Andric }
9848675466SDimitry Andric
9911d2b2d2SRoman Divacky break;
10011d2b2d2SRoman Divacky }
10111d2b2d2SRoman Divacky
10248675466SDimitry Andric if (OS.str().empty())
10377dbea07SDimitry Andric OS << BT.getDescription();
10448675466SDimitry Andric
10577dbea07SDimitry Andric auto R = std::make_unique<PathSensitiveBugReport>(BT, OS.str(), N);
10651fb8b01SRoman Divacky if (ex) {
10751fb8b01SRoman Divacky R->addRange(ex->getSourceRange());
108676fbe81SDimitry Andric bugreporter::trackExpressionValue(N, ex, *R);
10951fb8b01SRoman Divacky }
110c192b3dcSDimitry Andric C.emitReport(std::move(R));
11151fb8b01SRoman Divacky }
11251fb8b01SRoman Divacky
registerUndefinedAssignmentChecker(CheckerManager & mgr)11301af97d3SDimitry Andric void ento::registerUndefinedAssignmentChecker(CheckerManager &mgr) {
11401af97d3SDimitry Andric mgr.registerChecker<UndefinedAssignmentChecker>();
11501af97d3SDimitry Andric }
11622989816SDimitry Andric
shouldRegisterUndefinedAssignmentChecker(const CheckerManager & mgr)117cfca06d7SDimitry Andric bool ento::shouldRegisterUndefinedAssignmentChecker(const CheckerManager &mgr) {
11822989816SDimitry Andric return true;
11922989816SDimitry Andric }
120