Skip to content

Commit 0aea8ec

Browse files
authored
Merge pull request #3681 from haoNoQ/static-analyzer-cherrypicks-24
Static analyzer cherrypicks 24
2 parents 1c3f7aa + effbeb8 commit 0aea8ec

File tree

68 files changed

+3393
-433
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+3393
-433
lines changed

clang/cmake/modules/AddClang.cmake

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,12 @@ macro(add_clang_library name)
100100
# The Xcode generator doesn't handle object libraries correctly.
101101
list(APPEND LIBTYPE OBJECT)
102102
endif()
103-
set_property(GLOBAL APPEND PROPERTY CLANG_STATIC_LIBS ${name})
103+
if (NOT EXCLUDE_FROM_ALL)
104+
# Only include libraries that don't have EXCLUDE_FROM_ALL set. This
105+
# ensure that the clang static analyzer libraries are not compiled
106+
# as part of clang-shlib if CLANG_ENABLE_STATIC_ANALYZER=OFF.
107+
set_property(GLOBAL APPEND PROPERTY CLANG_STATIC_LIBS ${name})
108+
endif()
104109
endif()
105110
llvm_add_library(${name} ${LIBTYPE} ${ARG_UNPARSED_ARGUMENTS} ${srcs})
106111

@@ -110,8 +115,11 @@ macro(add_clang_library name)
110115
endif()
111116

112117
foreach(lib ${libs})
113-
if(TARGET ${lib})
118+
if(TARGET ${lib})
114119
target_link_libraries(${lib} INTERFACE ${LLVM_COMMON_LIBS})
120+
if (EXCLUDE_FROM_ALL)
121+
continue()
122+
endif()
115123

116124
if (NOT LLVM_INSTALL_TOOLCHAIN_ONLY OR ARG_INSTALL_WITH_TOOLCHAIN)
117125
get_target_export_arg(${name} Clang export_to_clangtargets UMBRELLA clang-libraries)

clang/docs/analyzer/checkers.rst

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2074,10 +2074,63 @@ Finds calls to the ``putenv`` function which pass a pointer to an automatic vari
20742074
if (retval < 0 || (size_t)retval >= sizeof(env)) {
20752075
/* Handle error */
20762076
}
2077-
2077+
20782078
return putenv(env); // putenv function should not be called with auto variables
20792079
}
2080-
2080+
2081+
alpha.security.cert.env
2082+
^^^^^^^^^^^^^^^^^^^^^^^
2083+
2084+
SEI CERT checkers of `POSIX C coding rules <https://wiki.sei.cmu.edu/confluence/x/JdcxBQ>`_.
2085+
2086+
.. _alpha-security-cert-env-InvalidPtr:
2087+
2088+
alpha.security.cert.env.InvalidPtr
2089+
"""""""""""""""""""""""""""
2090+
2091+
Corresponds to SEI CERT Rules ENV31-C and ENV34-C.
2092+
2093+
ENV31-C:
2094+
Rule is about the possible problem with `main` function's third argument, environment pointer,
2095+
"envp". When enviornment array is modified using some modification function
2096+
such as putenv, setenv or others, It may happen that memory is reallocated,
2097+
however "envp" is not updated to reflect the changes and points to old memory
2098+
region.
2099+
2100+
ENV34-C:
2101+
Some functions return a pointer to a statically allocated buffer.
2102+
Consequently, subsequent call of these functions will invalidate previous
2103+
pointer. These functions include: getenv, localeconv, asctime, setlocale, strerror
2104+
2105+
.. code-block:: c
2106+
2107+
int main(int argc, const char *argv[], const char *envp[]) {
2108+
if (setenv("MY_NEW_VAR", "new_value", 1) != 0) {
2109+
// setenv call may invalidate 'envp'
2110+
/* Handle error */
2111+
}
2112+
if (envp != NULL) {
2113+
for (size_t i = 0; envp[i] != NULL; ++i) {
2114+
puts(envp[i]);
2115+
// envp may no longer point to the current environment
2116+
// this program has unanticipated behavior, since envp
2117+
// does not reflect changes made by setenv function.
2118+
}
2119+
}
2120+
return 0;
2121+
}
2122+
2123+
void previous_call_invalidation() {
2124+
char *p, *pp;
2125+
2126+
p = getenv("VAR");
2127+
pp = getenv("VAR2");
2128+
// subsequent call to 'getenv' invalidated previous one
2129+
2130+
*p;
2131+
// dereferencing invalid pointer
2132+
}
2133+
20812134
.. _alpha-security-ArrayBound:
20822135
20832136
alpha.security.ArrayBound (C)

clang/include/clang/StaticAnalyzer/Checkers/Checkers.td

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ def Taint : Package<"taint">, ParentPackage<SecurityAlpha>;
7373

7474
def CERT : Package<"cert">, ParentPackage<SecurityAlpha>;
7575
def POS : Package<"pos">, ParentPackage<CERT>;
76+
def ENV : Package<"env">, ParentPackage<CERT>;
7677

7778
def Unix : Package<"unix">;
7879
def UnixAlpha : Package<"unix">, ParentPackage<Alpha>;
@@ -485,7 +486,17 @@ def DynamicMemoryModeling: Checker<"DynamicMemoryModeling">,
485486
"allocating and deallocating functions are annotated with "
486487
"ownership_holds, ownership_takes and ownership_returns.",
487488
"false",
488-
InAlpha>
489+
InAlpha>,
490+
CmdLineOption<Boolean,
491+
"AddNoOwnershipChangeNotes",
492+
"Add an additional note to the bug report for leak-like "
493+
"bugs. Dynamically allocated objects passed to functions "
494+
"that neither deallocated it, or have taken responsibility "
495+
"of the ownership are noted, similarly to "
496+
"NoStoreFuncVisitor.",
497+
"true",
498+
Released,
499+
Hide>
489500
]>,
490501
Dependencies<[CStringModeling]>,
491502
Documentation<NotDocumented>,
@@ -937,6 +948,14 @@ let ParentPackage = POS in {
937948

938949
} // end "alpha.cert.pos"
939950

951+
let ParentPackage = ENV in {
952+
953+
def InvalidPtrChecker : Checker<"InvalidPtr">,
954+
HelpText<"Finds usages of possibly invalidated pointers">,
955+
Documentation<HasDocumentation>;
956+
957+
} // end "alpha.cert.env"
958+
940959
let ParentPackage = SecurityAlpha in {
941960

942961
def ArrayBoundChecker : Checker<"ArrayBound">,

clang/include/clang/StaticAnalyzer/Core/AnalyzerOptions.def

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,22 @@ ANALYZER_OPTION(bool, ShouldDisplayCheckerNameForText, "display-checker-name",
320320
"Display the checker name for textual outputs",
321321
true)
322322

323+
ANALYZER_OPTION(
324+
bool, ShouldConsiderSingleElementArraysAsFlexibleArrayMembers,
325+
"consider-single-element-arrays-as-flexible-array-members",
326+
"Consider single element arrays as flexible array member candidates. "
327+
"This will prevent the analyzer from assuming that a single element array "
328+
"holds a single element.",
329+
false)
330+
331+
ANALYZER_OPTION(
332+
bool, ShouldAssumeControlledEnvironment, "assume-controlled-environment",
333+
"Whether the analyzed application runs in a controlled environment. "
334+
"We will assume that environment variables exist in queries and they hold "
335+
"no malicious data. For instance, if this option is enabled, 'getenv()' "
336+
"might be modeled by the analyzer to never return NULL.",
337+
false)
338+
323339
//===----------------------------------------------------------------------===//
324340
// Unsigned analyzer options.
325341
//===----------------------------------------------------------------------===//

clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "llvm/ADT/FoldingSet.h"
2222
#include "llvm/ADT/IntrusiveRefCntPtr.h"
2323
#include "llvm/ADT/STLExtras.h"
24+
#include "llvm/ADT/SmallPtrSet.h"
2425
#include "llvm/ADT/StringRef.h"
2526
#include <list>
2627
#include <memory>
@@ -622,8 +623,118 @@ class TagVisitor : public BugReporterVisitor {
622623
PathSensitiveBugReport &R) override;
623624
};
624625

625-
} // namespace ento
626+
class ObjCMethodCall;
627+
class CXXConstructorCall;
628+
629+
/// Put a diagnostic on return statement (or on } in its absence) of all inlined
630+
/// functions for which some property remained unchanged.
631+
/// Resulting diagnostics may read such as "Returning without writing to X".
632+
///
633+
/// Descendants can define what a "state change is", like a change of value
634+
/// to a memory region, liveness, etc. For function calls where the state did
635+
/// not change as defined, a custom note may be constructed.
636+
///
637+
/// For a minimal example, check out
638+
/// clang/unittests/StaticAnalyzer/NoStateChangeFuncVisitorTest.cpp.
639+
class NoStateChangeFuncVisitor : public BugReporterVisitor {
640+
private:
641+
/// Frames modifying the state as defined in \c wasModifiedBeforeCallExit.
642+
/// This visitor generates a note only if a function does *not* change the
643+
/// state that way. This information is not immediately available
644+
/// by looking at the node associated with the exit from the function
645+
/// (usually the return statement). To avoid recomputing the same information
646+
/// many times (going up the path for each node and checking whether the
647+
/// region was written into) we instead lazily compute the stack frames
648+
/// along the path.
649+
// TODO: Can't we just use a map instead? This is likely not as cheap as it
650+
// makes the code difficult to read.
651+
llvm::SmallPtrSet<const StackFrameContext *, 32> FramesModifying;
652+
llvm::SmallPtrSet<const StackFrameContext *, 32> FramesModifyingCalculated;
653+
654+
/// Check and lazily calculate whether the state is modified in the stack
655+
/// frame to which \p CallExitBeginN belongs.
656+
/// The calculation is cached in FramesModifying.
657+
bool isModifiedInFrame(const ExplodedNode *CallExitBeginN);
658+
659+
void markFrameAsModifying(const StackFrameContext *SCtx);
660+
661+
/// Write to \c FramesModifying all stack frames along the path in the current
662+
/// stack frame which modifies the state.
663+
void findModifyingFrames(const ExplodedNode *const CallExitBeginN);
626664

665+
protected:
666+
bugreporter::TrackingKind TKind;
667+
668+
/// \return Whether the state was modified from the current node, \p CurrN, to
669+
/// the end of the stack frame, at \p CallExitBeginN. \p CurrN and
670+
/// \p CallExitBeginN are always in the same stack frame.
671+
/// Clients should override this callback when a state change is important
672+
/// not only on the entire function call, but inside of it as well.
673+
/// Example: we may want to leave a note about the lack of locking/unlocking
674+
/// on a particular mutex, but not if inside the function its state was
675+
/// changed, but also restored. wasModifiedInFunction() wouldn't know of this
676+
/// change.
677+
virtual bool wasModifiedBeforeCallExit(const ExplodedNode *CurrN,
678+
const ExplodedNode *CallExitBeginN) {
679+
return false;
680+
}
681+
682+
/// \return Whether the state was modified in the inlined function call in
683+
/// between \p CallEnterN and \p CallExitEndN. Mind that the stack frame
684+
/// retrieved from a CallEnterN and CallExitEndN is the *caller's* stack
685+
/// frame! The inlined function's stack should be retrieved from either the
686+
/// immediate successor to \p CallEnterN or immediate predecessor to
687+
/// \p CallExitEndN.
688+
/// Clients should override this function if a state changes local to the
689+
/// inlined function are not interesting, only the change occuring as a
690+
/// result of it.
691+
/// Example: we want to leave a not about a leaked resource object not being
692+
/// deallocated / its ownership changed inside a function, and we don't care
693+
/// if it was assigned to a local variable (its change in ownership is
694+
/// inconsequential).
695+
virtual bool wasModifiedInFunction(const ExplodedNode *CallEnterN,
696+
const ExplodedNode *CallExitEndN) {
697+
return false;
698+
}
699+
700+
/// Consume the information on the non-modifying stack frame in order to
701+
/// either emit a note or not. May suppress the report entirely.
702+
/// \return Diagnostics piece for the unmodified state in the current
703+
/// function, if it decides to emit one. A good description might start with
704+
/// "Returning without...".
705+
virtual PathDiagnosticPieceRef
706+
maybeEmitNoteForObjCSelf(PathSensitiveBugReport &R,
707+
const ObjCMethodCall &Call,
708+
const ExplodedNode *N) = 0;
709+
710+
/// Consume the information on the non-modifying stack frame in order to
711+
/// either emit a note or not. May suppress the report entirely.
712+
/// \return Diagnostics piece for the unmodified state in the current
713+
/// function, if it decides to emit one. A good description might start with
714+
/// "Returning without...".
715+
virtual PathDiagnosticPieceRef
716+
maybeEmitNoteForCXXThis(PathSensitiveBugReport &R,
717+
const CXXConstructorCall &Call,
718+
const ExplodedNode *N) = 0;
719+
720+
/// Consume the information on the non-modifying stack frame in order to
721+
/// either emit a note or not. May suppress the report entirely.
722+
/// \return Diagnostics piece for the unmodified state in the current
723+
/// function, if it decides to emit one. A good description might start with
724+
/// "Returning without...".
725+
virtual PathDiagnosticPieceRef
726+
maybeEmitNoteForParameters(PathSensitiveBugReport &R, const CallEvent &Call,
727+
const ExplodedNode *N) = 0;
728+
729+
public:
730+
NoStateChangeFuncVisitor(bugreporter::TrackingKind TKind) : TKind(TKind) {}
731+
732+
PathDiagnosticPieceRef VisitNode(const ExplodedNode *N,
733+
BugReporterContext &BR,
734+
PathSensitiveBugReport &R) override final;
735+
};
736+
737+
} // namespace ento
627738
} // namespace clang
628739

629740
#endif // LLVM_CLANG_STATICANALYZER_CORE_BUGREPORTER_BUGREPORTERVISITORS_H

clang/include/clang/StaticAnalyzer/Core/PathSensitive/RangedConstraintManager.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ class Range {
4848
ID.AddPointer(&To());
4949
}
5050
void dump(raw_ostream &OS) const;
51+
void dump() const;
5152

5253
// In order to keep non-overlapping ranges sorted, we can compare only From
5354
// points.
@@ -282,6 +283,7 @@ class RangeSet {
282283
bool contains(llvm::APSInt Point) const { return containsImpl(Point); }
283284

284285
void dump(raw_ostream &OS) const;
286+
void dump() const;
285287

286288
bool operator==(const RangeSet &Other) const { return *Impl == *Other.Impl; }
287289
bool operator!=(const RangeSet &Other) const { return !(*this == Other); }

clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333

3434
namespace clang {
3535

36+
class AnalyzerOptions;
3637
class BlockDecl;
3738
class CXXBoolLiteralExpr;
3839
class CXXMethodDecl;
@@ -66,6 +67,8 @@ class SValBuilder {
6667

6768
ProgramStateManager &StateMgr;
6869

70+
const AnalyzerOptions &AnOpts;
71+
6972
/// The scalar type to use for array indices.
7073
const QualType ArrayIndexTy;
7174

@@ -96,11 +99,7 @@ class SValBuilder {
9699

97100
public:
98101
SValBuilder(llvm::BumpPtrAllocator &alloc, ASTContext &context,
99-
ProgramStateManager &stateMgr)
100-
: Context(context), BasicVals(context, alloc),
101-
SymMgr(context, BasicVals, alloc), MemMgr(context, alloc),
102-
StateMgr(stateMgr), ArrayIndexTy(context.LongLongTy),
103-
ArrayIndexWidth(context.getTypeSize(ArrayIndexTy)) {}
102+
ProgramStateManager &stateMgr);
104103

105104
virtual ~SValBuilder() = default;
106105

@@ -188,6 +187,8 @@ class SValBuilder {
188187
MemRegionManager &getRegionManager() { return MemMgr; }
189188
const MemRegionManager &getRegionManager() const { return MemMgr; }
190189

190+
const AnalyzerOptions &getAnalyzerOptions() const { return AnOpts; }
191+
191192
// Forwarding methods to SymbolManager.
192193

193194
const SymbolConjured* conjureSymbol(const Stmt *stmt,

clang/lib/Sema/SemaStmt.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3489,7 +3489,8 @@ VerifyInitializationSequenceCXX98(const Sema &S,
34893489
ExprResult Sema::PerformMoveOrCopyInitialization(
34903490
const InitializedEntity &Entity, const NamedReturnInfo &NRInfo, Expr *Value,
34913491
bool SupressSimplerImplicitMoves) {
3492-
if ((!getLangOpts().CPlusPlus2b || SupressSimplerImplicitMoves) &&
3492+
if (getLangOpts().CPlusPlus &&
3493+
(!getLangOpts().CPlusPlus2b || SupressSimplerImplicitMoves) &&
34933494
NRInfo.isMoveEligible()) {
34943495
ImplicitCastExpr AsRvalue(ImplicitCastExpr::OnStack, Value->getType(),
34953496
CK_NoOp, Value, VK_XValue, FPOptionsOverride());
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# These directories can significantly impact build time, only build
2+
# them if anything depends on the clangStaticAnalyzer* libraries.
3+
if(NOT CLANG_ENABLE_STATIC_ANALYZER)
4+
set_property(DIRECTORY PROPERTY EXCLUDE_FROM_ALL ON)
5+
set(EXCLUDE_FROM_ALL ON)
6+
endif()
7+
18
add_subdirectory(Core)
29
add_subdirectory(Checkers)
310
add_subdirectory(Frontend)

clang/lib/StaticAnalyzer/Checkers/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ add_clang_library(clangStaticAnalyzerCheckers
4949
IdenticalExprChecker.cpp
5050
InnerPointerChecker.cpp
5151
InvalidatedIteratorChecker.cpp
52+
cert/InvalidPtrChecker.cpp
5253
Iterator.cpp
5354
IteratorModeling.cpp
5455
IteratorRangeChecker.cpp

0 commit comments

Comments
 (0)