clang 22.0.0git
StoreToImmutableChecker.cpp
Go to the documentation of this file.
1//=== StoreToImmutableChecker.cpp - Store to immutable memory ---*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines StoreToImmutableChecker, a checker that detects writes
10// to immutable memory regions. This implements part of SEI CERT Rule ENV30-C.
11//
12//===----------------------------------------------------------------------===//
13
20
21using namespace clang;
22using namespace ento;
23
24namespace {
25class StoreToImmutableChecker : public Checker<check::Bind> {
26 const BugType BT{this, "Write to immutable memory", "CERT Environment (ENV)"};
27
28public:
29 void checkBind(SVal Loc, SVal Val, const Stmt *S, bool AtDeclInit,
30 CheckerContext &C) const;
31};
32} // end anonymous namespace
33
35 if (isa<GlobalImmutableSpaceRegion>(MR))
36 return true;
37
38 // Check if this is a TypedRegion with a const-qualified type
39 if (const auto *TR = dyn_cast<TypedRegion>(MR)) {
40 QualType LocationType = TR->getDesugaredLocationType(C.getASTContext());
41 if (LocationType->isPointerOrReferenceType())
42 LocationType = LocationType->getPointeeType();
43 if (LocationType.isConstQualified())
44 return true;
45 }
46
47 // Check if this is a SymbolicRegion with a const-qualified pointee type
48 if (const auto *SR = dyn_cast<SymbolicRegion>(MR)) {
49 QualType PointeeType = SR->getPointeeStaticType();
50 if (PointeeType.isConstQualified())
51 return true;
52 }
53
54 // NOTE: The above branches do not cover AllocaRegion. We do not need to check
55 // AllocaRegion, as it models untyped memory, that is allocated on the stack.
56
57 return false;
58}
59
62 while (true) {
64 return MR;
65 if (auto *SR = dyn_cast<SubRegion>(MR))
66 MR = SR->getSuperRegion();
67 else
68 return nullptr;
69 }
70}
71
72static const DeclRegion *
74 while (true) {
75 if (const auto *DR = dyn_cast<DeclRegion>(MR)) {
76 const ValueDecl *D = DR->getDecl();
77 QualType DeclaredType = D->getType();
78 if (DeclaredType.isConstQualified())
79 return DR;
80 }
81 if (auto *SR = dyn_cast<SubRegion>(MR))
82 MR = SR->getSuperRegion();
83 else
84 return nullptr;
85 }
86}
87
88void StoreToImmutableChecker::checkBind(SVal Loc, SVal Val, const Stmt *S,
89 bool AtDeclInit,
90 CheckerContext &C) const {
91 // We are only interested in stores to memory regions
92 const MemRegion *MR = Loc.getAsRegion();
93 if (!MR)
94 return;
95
96 // Skip variable declarations and initializations - we only want to catch
97 // actual writes
98 if (AtDeclInit)
99 return;
100
101 // Check if the region is in the global immutable space
102 const MemSpaceRegion *MS = MR->getMemorySpace(C.getState());
103 const bool IsGlobalImmutableSpace = isa<GlobalImmutableSpaceRegion>(MS);
104 // Check if the region corresponds to a const variable
105 const MemRegion *InnermostConstRegion = getInnermostConstRegion(MR, C);
106 if (!IsGlobalImmutableSpace && !InnermostConstRegion)
107 return;
108
109 SmallString<64> WarningMessage{"Trying to write to immutable memory"};
110 if (IsGlobalImmutableSpace)
111 WarningMessage += " in global read-only storage";
112
113 // Generate the bug report
114 ExplodedNode *N = C.generateNonFatalErrorNode();
115 if (!N)
116 return;
117
118 auto R = std::make_unique<PathSensitiveBugReport>(BT, WarningMessage, N);
119 R->addRange(S->getSourceRange());
120
121 // Generate a note if the location that is being written to has a
122 // declaration or if it is a subregion of a const region with a declaration.
123 const DeclRegion *DR =
124 getInnermostEnclosingConstDeclRegion(InnermostConstRegion, C);
125 if (DR) {
126 const char *NoteMessage =
127 (DR != MR) ? "Enclosing memory region is declared as immutable here"
128 : "Memory region is declared as immutable here";
129 R->addNote(NoteMessage, PathDiagnosticLocation::create(
130 DR->getDecl(), C.getSourceManager()));
131 }
132
133 // For this checker, we are only interested in the value being written, no
134 // need to mark the value being assigned interesting.
135
136 C.emitReport(std::move(R));
137}
138
139void ento::registerStoreToImmutableChecker(CheckerManager &mgr) {
140 mgr.registerChecker<StoreToImmutableChecker>();
141}
142
143bool ento::shouldRegisterStoreToImmutableChecker(const CheckerManager &mgr) {
144 return true;
145}
const Decl * D
static const MemRegion * getInnermostConstRegion(const MemRegion *MR, CheckerContext &C)
static const DeclRegion * getInnermostEnclosingConstDeclRegion(const MemRegion *MR, CheckerContext &C)
static bool isEffectivelyConstRegion(const MemRegion *MR, CheckerContext &C)
A (possibly-)qualified type.
Definition: TypeBase.h:937
bool isConstQualified() const
Determine whether this type is const-qualified.
Definition: TypeBase.h:8416
Stmt - This represents one statement.
Definition: Stmt.h:85
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee.
Definition: Type.cpp:752
bool isPointerOrReferenceType() const
Definition: TypeBase.h:8584
Represent the declaration of a variable (in which case it is an lvalue) a function (in which case it ...
Definition: Decl.h:711
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
Definition: Checker.h:553
virtual const ValueDecl * getDecl() const =0
MemRegion - The root abstract class for all memory regions.
Definition: MemRegion.h:98
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace(ProgramStateRef State) const
Returns the most specific memory space for this memory region in the given ProgramStateRef.
Definition: MemRegion.cpp:1397
MemSpaceRegion - A memory region that represents a "memory space"; for example, the set of global var...
Definition: MemRegion.h:236
static PathDiagnosticLocation create(const Decl *D, const SourceManager &SM)
Create a location corresponding to the given declaration.
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition: SVals.h:56
const MemRegion * getAsRegion() const
Definition: SVals.cpp:119
The JSON file list parser is used to communicate input to InstallAPI.