Merge llvm-project main llvmorg-18-init-16003-gfc5f51cf5af4

This updates llvm, clang, compiler-rt, libc++, libunwind, lld, lldb and
openmp to llvm-project main llvmorg-18-init-16003-gfc5f51cf5af4.

PR:		276104
MFC after:	1 month
This commit is contained in:
Dimitry Andric 2024-01-03 19:04:11 +01:00
commit 647cbc5de8
335 changed files with 5215 additions and 3743 deletions

View File

@ -136,11 +136,14 @@ OLD_FILES+=usr/lib/clang/17/include/cmpccxaddintrin.h
OLD_FILES+=usr/lib/clang/17/include/cpuid.h
OLD_FILES+=usr/lib/clang/17/include/crc32intrin.h
OLD_FILES+=usr/lib/clang/17/include/cuda_wrappers/algorithm
OLD_FILES+=usr/lib/clang/17/include/cuda_wrappers/bits/basic_string.h
OLD_FILES+=usr/lib/clang/17/include/cuda_wrappers/bits/basic_string.tcc
OLD_FILES+=usr/lib/clang/17/include/cuda_wrappers/bits/shared_ptr_base.h
OLD_DIRS+=usr/lib/clang/17/include/cuda_wrappers/bits
OLD_FILES+=usr/lib/clang/17/include/cuda_wrappers/cmath
OLD_FILES+=usr/lib/clang/17/include/cuda_wrappers/complex
OLD_FILES+=usr/lib/clang/17/include/cuda_wrappers/new
OLD_FILES+=usr/lib/clang/17/include/cuda_wrappers/shared_ptr_base.h
OLD_DIRS+=usr/lib/clang/17/include/cuda_wrappers
OLD_FILES+=usr/lib/clang/17/include/emmintrin.h
OLD_FILES+=usr/lib/clang/17/include/enqcmdintrin.h
@ -440,57 +443,57 @@ OLD_DIRS+=usr/lib/clang/17/share
OLD_DIRS+=usr/lib/clang/17
# 2024mmdd: new libc++ import which bumps version from 17 to 18
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/algorithm_fwd.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/algorithm_impl.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/execution_defs.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/execution_impl.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/glue_algorithm_defs.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/glue_algorithm_impl.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/glue_memory_defs.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/glue_memory_impl.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/glue_numeric_defs.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/glue_numeric_impl.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/memory_impl.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/numeric_fwd.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/numeric_impl.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/omp/parallel_for.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/omp/parallel_for_each.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/omp/parallel_invoke.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/omp/parallel_merge.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/omp/parallel_scan.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/omp/parallel_stable_partial_sort.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/omp/parallel_stable_sort.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/omp/parallel_transform_reduce.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/omp/parallel_transform_scan.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/omp/util.h
OLD_DIRS+=usr/include/include/c++/v1/__pstl/internal/omp
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/parallel_backend.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/parallel_backend_omp.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/parallel_backend_serial.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/parallel_backend_tbb.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/parallel_backend_utils.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/unseq_backend_simd.h
OLD_FILES+=usr/include/include/c++/v1/__pstl/internal/utils.h
OLD_DIRS+=usr/include/include/c++/v1/__pstl/internal
OLD_DIRS+=usr/include/include/c++/v1/__pstl
OLD_FILES+=usr/include/include/c++/v1/__pstl_algorithm
OLD_FILES+=usr/include/include/c++/v1/__pstl_memory
OLD_FILES+=usr/include/include/c++/v1/__pstl_numeric
OLD_FILES+=usr/include/include/c++/v1/__type_traits/predicate_traits.h
OLD_FILES+=usr/include/include/c++/v1/__utility/terminate_on_exception.h
OLD_FILES+=usr/include/include/c++/v1/experimental/deque
OLD_FILES+=usr/include/include/c++/v1/experimental/forward_list
OLD_FILES+=usr/include/include/c++/v1/experimental/list
OLD_FILES+=usr/include/include/c++/v1/experimental/map
OLD_FILES+=usr/include/include/c++/v1/experimental/memory_resource
OLD_FILES+=usr/include/include/c++/v1/experimental/regex
OLD_FILES+=usr/include/include/c++/v1/experimental/set
OLD_FILES+=usr/include/include/c++/v1/experimental/string
OLD_FILES+=usr/include/include/c++/v1/experimental/unordered_map
OLD_FILES+=usr/include/include/c++/v1/experimental/unordered_set
OLD_FILES+=usr/include/include/c++/v1/experimental/vector
OLD_FILES+=usr/include/include/c++/v1/limits.h
OLD_FILES+=usr/include/include/c++/v1/setjmp.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/algorithm_fwd.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/algorithm_impl.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/execution_defs.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/execution_impl.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/glue_algorithm_defs.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/glue_algorithm_impl.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/glue_memory_defs.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/glue_memory_impl.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/glue_numeric_defs.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/glue_numeric_impl.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/memory_impl.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/numeric_fwd.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/numeric_impl.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/omp/parallel_for.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/omp/parallel_for_each.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/omp/parallel_invoke.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/omp/parallel_merge.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/omp/parallel_scan.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/omp/parallel_stable_partial_sort.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/omp/parallel_stable_sort.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/omp/parallel_transform_reduce.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/omp/parallel_transform_scan.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/omp/util.h
OLD_DIRS+=usr/include/c++/v1/__pstl/internal/omp
OLD_FILES+=usr/include/c++/v1/__pstl/internal/parallel_backend.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/parallel_backend_omp.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/parallel_backend_serial.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/parallel_backend_tbb.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/parallel_backend_utils.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/unseq_backend_simd.h
OLD_FILES+=usr/include/c++/v1/__pstl/internal/utils.h
OLD_DIRS+=usr/include/c++/v1/__pstl/internal
OLD_DIRS+=usr/include/c++/v1/__pstl
OLD_FILES+=usr/include/c++/v1/__pstl_algorithm
OLD_FILES+=usr/include/c++/v1/__pstl_memory
OLD_FILES+=usr/include/c++/v1/__pstl_numeric
OLD_FILES+=usr/include/c++/v1/__type_traits/predicate_traits.h
OLD_FILES+=usr/include/c++/v1/__utility/terminate_on_exception.h
OLD_FILES+=usr/include/c++/v1/experimental/deque
OLD_FILES+=usr/include/c++/v1/experimental/forward_list
OLD_FILES+=usr/include/c++/v1/experimental/list
OLD_FILES+=usr/include/c++/v1/experimental/map
OLD_FILES+=usr/include/c++/v1/experimental/memory_resource
OLD_FILES+=usr/include/c++/v1/experimental/regex
OLD_FILES+=usr/include/c++/v1/experimental/set
OLD_FILES+=usr/include/c++/v1/experimental/string
OLD_FILES+=usr/include/c++/v1/experimental/unordered_map
OLD_FILES+=usr/include/c++/v1/experimental/unordered_set
OLD_FILES+=usr/include/c++/v1/experimental/vector
OLD_FILES+=usr/include/c++/v1/limits.h
OLD_FILES+=usr/include/c++/v1/setjmp.h
# 20240321: remove empty /usr/libdata/gcc directory
OLD_DIRS+=usr/libdata/gcc

View File

@ -2383,10 +2383,6 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
/// Check if the type is the CUDA device builtin texture type.
bool isCUDADeviceBuiltinTextureType() const;
bool isRVVType(unsigned ElementCount) const;
bool isRVVType(unsigned Bitwidth, bool IsFloat, bool IsBFloat = false) const;
/// Return the implicit lifetime for this type, which must not be dependent.
Qualifiers::ObjCLifetime getObjCARCImplicitLifetime() const;
@ -7283,28 +7279,6 @@ inline bool Type::isOpenCLSpecificType() const {
isQueueT() || isReserveIDT() || isPipeType() || isOCLExtOpaqueType();
}
inline bool Type::isRVVType(unsigned ElementCount) const {
bool Ret = false;
#define RVV_VECTOR_TYPE(Name, Id, SingletonId, NumEls, ElBits, NF, IsSigned, \
IsFP, IsBF) \
if (NumEls == ElementCount) \
Ret |= isSpecificBuiltinType(BuiltinType::Id);
#include "clang/Basic/RISCVVTypes.def"
return Ret;
}
inline bool Type::isRVVType(unsigned Bitwidth, bool IsFloat,
bool IsBFloat) const {
bool Ret = false;
#define RVV_TYPE(Name, Id, SingletonId)
#define RVV_VECTOR_TYPE(Name, Id, SingletonId, NumEls, ElBits, NF, IsSigned, \
IsFP, IsBF) \
if (ElBits == Bitwidth && IsFloat == IsFP && IsBFloat == IsBF) \
Ret |= isSpecificBuiltinType(BuiltinType::Id);
#include "clang/Basic/RISCVVTypes.def"
return Ret;
}
inline bool Type::isTemplateTypeParmType() const {
return isa<TemplateTypeParmType>(CanonicalType);
}

View File

@ -68,6 +68,9 @@ TARGET_BUILTIN(__builtin_arm_ldg, "v*v*", "t", "mte")
TARGET_BUILTIN(__builtin_arm_stg, "vv*", "t", "mte")
TARGET_BUILTIN(__builtin_arm_subp, "Uiv*v*", "t", "mte")
// SME state function
BUILTIN(__builtin_arm_get_sme_state, "vULi*ULi*", "n")
// Memory Operations
TARGET_BUILTIN(__builtin_arm_mops_memset_tag, "v*v*iz", "", "mte,mops")

View File

@ -109,10 +109,10 @@ multiclass RVVVFWMACCBuiltinSet<list<list<string>> suffixes_prototypes> {
Name = NAME,
HasMasked = false,
Log2LMUL = [-2, -1, 0, 1, 2] in
defm NAME : RVVOutOp1Op2BuiltinSet<NAME, "b", suffixes_prototypes>;
defm NAME : RVVOutOp1Op2BuiltinSet<NAME, "y", suffixes_prototypes>;
}
multiclass RVVVQMACCBuiltinSet<list<list<string>> suffixes_prototypes> {
multiclass RVVVQMACCDODBuiltinSet<list<list<string>> suffixes_prototypes> {
let OverloadedName = NAME,
Name = NAME,
HasMasked = false,
@ -120,6 +120,14 @@ multiclass RVVVQMACCBuiltinSet<list<list<string>> suffixes_prototypes> {
defm NAME : RVVOutOp1Op2BuiltinSet<NAME, "i", suffixes_prototypes>;
}
multiclass RVVVQMACCQOQBuiltinSet<list<list<string>> suffixes_prototypes> {
let OverloadedName = NAME,
Name = NAME,
HasMasked = false,
Log2LMUL = [-1, 0, 1, 2] in
defm NAME : RVVOutOp1Op2BuiltinSet<NAME, "s", suffixes_prototypes>;
}
multiclass RVVVFNRCLIPBuiltinSet<string suffix, string prototype, string type_range> {
let Log2LMUL = [-3, -2, -1, 0, 1, 2],
Name = NAME,
@ -130,18 +138,18 @@ multiclass RVVVFNRCLIPBuiltinSet<string suffix, string prototype, string type_ra
let UnMaskedPolicyScheme = HasPolicyOperand in
let RequiredFeatures = ["Xsfvqmaccdod"] in {
defm sf_vqmaccu_2x8x2 : RVVVQMACCBuiltinSet<[["", "v", "vv(FixedSEW:8)SUv(FixedSEW:8)Uv"]]>;
defm sf_vqmacc_2x8x2 : RVVVQMACCBuiltinSet<[["", "v", "vv(FixedSEW:8)Sv(FixedSEW:8)v"]]>;
defm sf_vqmaccus_2x8x2 : RVVVQMACCBuiltinSet<[["", "v", "vv(FixedSEW:8)SUv(FixedSEW:8)v"]]>;
defm sf_vqmaccsu_2x8x2 : RVVVQMACCBuiltinSet<[["", "v", "vv(FixedSEW:8)Sv(FixedSEW:8)Uv"]]>;
defm sf_vqmaccu_2x8x2 : RVVVQMACCDODBuiltinSet<[["", "v", "vv(FixedSEW:8)SUv(FixedSEW:8)Uv"]]>;
defm sf_vqmacc_2x8x2 : RVVVQMACCDODBuiltinSet<[["", "v", "vv(FixedSEW:8)Sv(FixedSEW:8)v"]]>;
defm sf_vqmaccus_2x8x2 : RVVVQMACCDODBuiltinSet<[["", "v", "vv(FixedSEW:8)SUv(FixedSEW:8)v"]]>;
defm sf_vqmaccsu_2x8x2 : RVVVQMACCDODBuiltinSet<[["", "v", "vv(FixedSEW:8)Sv(FixedSEW:8)Uv"]]>;
}
let UnMaskedPolicyScheme = HasPolicyOperand in
let RequiredFeatures = ["Xsfvqmaccqoq"] in {
defm sf_vqmaccu_4x8x4 : RVVVQMACCBuiltinSet<[["", "v", "vv(FixedSEW:8)SUv(FixedSEW:8)Uv"]]>;
defm sf_vqmacc_4x8x4 : RVVVQMACCBuiltinSet<[["", "v", "vv(FixedSEW:8)Sv(FixedSEW:8)v"]]>;
defm sf_vqmaccus_4x8x4 : RVVVQMACCBuiltinSet<[["", "v", "vv(FixedSEW:8)SUv(FixedSEW:8)v"]]>;
defm sf_vqmaccsu_4x8x4 : RVVVQMACCBuiltinSet<[["", "v", "vv(FixedSEW:8)Sv(FixedSEW:8)Uv"]]>;
defm sf_vqmaccu_4x8x4 : RVVVQMACCQOQBuiltinSet<[["", "w", "ww(FixedSEW:8)SUv(FixedSEW:8)Uv"]]>;
defm sf_vqmacc_4x8x4 : RVVVQMACCQOQBuiltinSet<[["", "w", "ww(FixedSEW:8)Sv(FixedSEW:8)v"]]>;
defm sf_vqmaccus_4x8x4 : RVVVQMACCQOQBuiltinSet<[["", "w", "ww(FixedSEW:8)SUv(FixedSEW:8)v"]]>;
defm sf_vqmaccsu_4x8x4 : RVVVQMACCQOQBuiltinSet<[["", "w", "ww(FixedSEW:8)Sv(FixedSEW:8)Uv"]]>;
}
let UnMaskedPolicyScheme = HasPolicyOperand in

View File

@ -2441,11 +2441,9 @@ let HasMasked = false, HasVL = false, IRName = "" in {
return Builder.CreateInsertVector(ResultType, Ops[0], Ops[2], Ops[1]);
}
}] in {
let Log2LMUL = [0, 1, 2] in {
foreach dst_lmul = ["(LFixedLog2LMUL:1)", "(LFixedLog2LMUL:2)", "(LFixedLog2LMUL:3)"] in {
def : RVVBuiltin<"v" # dst_lmul # "v", dst_lmul # "v" # dst_lmul # "vKzv", "csilxfd">;
def : RVVBuiltin<"Uv" # dst_lmul # "Uv", dst_lmul # "Uv" # dst_lmul #"UvKzUv", "csil">;
}
foreach dst_lmul = ["(LFixedLog2LMUL:1)", "(LFixedLog2LMUL:2)", "(LFixedLog2LMUL:3)"] in {
def : RVVBuiltin<"v" # dst_lmul # "v", dst_lmul # "v" # dst_lmul # "vKzv", "csilxfd">;
def : RVVBuiltin<"Uv" # dst_lmul # "Uv", dst_lmul # "Uv" # dst_lmul #"UvKzUv", "csil">;
}
foreach nf = NFList in {
defvar T = "(Tuple:" # nf # ")";

View File

@ -41,7 +41,7 @@
// x: float16_t (half)
// f: float32_t (float)
// d: float64_t (double)
// b: bfloat16_t (bfloat16)
// y: bfloat16_t (bfloat16)
//
// This way, given an LMUL, a record with a TypeRange "sil" will cause the
// definition of 3 builtins. Each type "t" in the TypeRange (in this example

View File

@ -13,6 +13,7 @@
namespace clang {
namespace ento {
namespace categories {
extern const char *const AppleAPIMisuse;
extern const char *const CoreFoundationObjectiveC;
extern const char *const LogicError;
extern const char *const MemoryRefCount;

View File

@ -193,9 +193,8 @@ class PostCall {
class Location {
template <typename CHECKER>
static void _checkLocation(void *checker,
const SVal &location, bool isLoad, const Stmt *S,
CheckerContext &C) {
static void _checkLocation(void *checker, SVal location, bool isLoad,
const Stmt *S, CheckerContext &C) {
((const CHECKER *)checker)->checkLocation(location, isLoad, S, C);
}
@ -209,8 +208,7 @@ class Location {
class Bind {
template <typename CHECKER>
static void _checkBind(void *checker,
const SVal &location, const SVal &val, const Stmt *S,
static void _checkBind(void *checker, SVal location, SVal val, const Stmt *S,
CheckerContext &C) {
((const CHECKER *)checker)->checkBind(location, val, S, C);
}
@ -456,10 +454,8 @@ namespace eval {
class Assume {
template <typename CHECKER>
static ProgramStateRef _evalAssume(void *checker,
ProgramStateRef state,
const SVal &cond,
bool assumption) {
static ProgramStateRef _evalAssume(void *checker, ProgramStateRef state,
SVal cond, bool assumption) {
return ((const CHECKER *)checker)->evalAssume(state, cond, assumption);
}

View File

@ -488,13 +488,11 @@ class CheckerManager {
using CheckCallFunc =
CheckerFn<void (const CallEvent &, CheckerContext &)>;
using CheckLocationFunc =
CheckerFn<void (const SVal &location, bool isLoad, const Stmt *S,
CheckerContext &)>;
using CheckLocationFunc = CheckerFn<void(SVal location, bool isLoad,
const Stmt *S, CheckerContext &)>;
using CheckBindFunc =
CheckerFn<void (const SVal &location, const SVal &val, const Stmt *S,
CheckerContext &)>;
CheckerFn<void(SVal location, SVal val, const Stmt *S, CheckerContext &)>;
using CheckEndAnalysisFunc =
CheckerFn<void (ExplodedGraph &, BugReporter &, ExprEngine &)>;
@ -530,8 +528,7 @@ class CheckerManager {
RegionAndSymbolInvalidationTraits *ITraits)>;
using EvalAssumeFunc =
CheckerFn<ProgramStateRef (ProgramStateRef, const SVal &cond,
bool assumption)>;
CheckerFn<ProgramStateRef(ProgramStateRef, SVal cond, bool assumption)>;
using EvalCallFunc = CheckerFn<bool (const CallEvent &, CheckerContext &)>;

View File

@ -37,7 +37,6 @@
namespace clang {
namespace interp {
using APInt = llvm::APInt;
using APSInt = llvm::APSInt;
/// Convert a value to an APValue.

View File

@ -299,10 +299,8 @@ class Parser::CodeTokenizer {
/// Consume all leading whitespace from \c Code.
void consumeWhitespace() {
Code = Code.drop_while([](char c) {
// Don't trim newlines.
return StringRef(" \t\v\f\r").contains(c);
});
// Don't trim newlines.
Code = Code.ltrim(" \t\v\f\r");
}
SourceLocation currentLocation() {

View File

@ -628,8 +628,7 @@ ObjCMethodFamily Selector::getMethodFamilyImpl(Selector sel) {
return OMF_performSelector;
// The other method families may begin with a prefix of underscores.
while (!name.empty() && name.front() == '_')
name = name.substr(1);
name = name.ltrim('_');
if (name.empty()) return OMF_None;
switch (name.front()) {

View File

@ -1365,8 +1365,7 @@ bool AArch64TargetInfo::validateConstraintModifier(
StringRef Constraint, char Modifier, unsigned Size,
std::string &SuggestedModifier) const {
// Strip off constraint modifiers.
while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&')
Constraint = Constraint.substr(1);
Constraint = Constraint.ltrim("=+&");
switch (Constraint[0]) {
default:

View File

@ -1230,8 +1230,7 @@ bool ARMTargetInfo::validateConstraintModifier(
bool isInOut = (Constraint[0] == '+');
// Strip off constraint modifiers.
while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&')
Constraint = Constraint.substr(1);
Constraint = Constraint.ltrim("=+&");
switch (Constraint[0]) {
default:

View File

@ -416,8 +416,7 @@ static void handleFullArchString(StringRef FullArchStr,
Features.push_back("__RISCV_TargetAttrNeedOverride");
auto RII = llvm::RISCVISAInfo::parseArchString(
FullArchStr, /* EnableExperimentalExtension */ true);
if (!RII) {
consumeError(RII.takeError());
if (llvm::errorToBool(RII.takeError())) {
// Forward the invalid FullArchStr.
Features.push_back("+" + FullArchStr.str());
} else {

View File

@ -1613,8 +1613,7 @@ bool X86TargetInfo::validateOutputSize(const llvm::StringMap<bool> &FeatureMap,
StringRef Constraint,
unsigned Size) const {
// Strip off constraint modifiers.
while (Constraint[0] == '=' || Constraint[0] == '+' || Constraint[0] == '&')
Constraint = Constraint.substr(1);
Constraint = Constraint.ltrim("=+&");
return validateOperandSize(FeatureMap, Constraint, Size);
}

View File

@ -96,11 +96,7 @@ void clang::ProcessWarningOptions(DiagnosticsEngine &Diags,
// Check to see if this warning starts with "no-", if so, this is a
// negative form of the option.
bool isPositive = true;
if (Opt.starts_with("no-")) {
isPositive = false;
Opt = Opt.substr(3);
}
bool isPositive = !Opt.consume_front("no-");
// Figure out how this option affects the warning. If -Wfoo, map the
// diagnostic to a warning, if -Wno-foo, map it to ignore.

View File

@ -10430,6 +10430,26 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
return Builder.CreateCall(F, llvm::ConstantInt::get(Int32Ty, HintID));
}
if (BuiltinID == clang::AArch64::BI__builtin_arm_get_sme_state) {
// Create call to __arm_sme_state and store the results to the two pointers.
CallInst *CI = EmitRuntimeCall(CGM.CreateRuntimeFunction(
llvm::FunctionType::get(StructType::get(CGM.Int64Ty, CGM.Int64Ty), {},
false),
"__arm_sme_state"));
auto Attrs =
AttributeList()
.addFnAttribute(getLLVMContext(), "aarch64_pstate_sm_compatible")
.addFnAttribute(getLLVMContext(), "aarch64_pstate_za_preserved");
CI->setAttributes(Attrs);
CI->setCallingConv(
llvm::CallingConv::
AArch64_SME_ABI_Support_Routines_PreserveMost_From_X2);
Builder.CreateStore(Builder.CreateExtractValue(CI, 0),
EmitPointerWithAlignment(E->getArg(0)));
return Builder.CreateStore(Builder.CreateExtractValue(CI, 1),
EmitPointerWithAlignment(E->getArg(1)));
}
if (BuiltinID == clang::AArch64::BI__builtin_arm_rbit) {
assert((getContext().getTypeSize(E->getType()) == 32) &&
"rbit of unusual size!");

View File

@ -6406,13 +6406,11 @@ static void emitOMPAtomicCaptureExpr(CodeGenFunction &CGF,
}
}
static void emitOMPAtomicCompareExpr(CodeGenFunction &CGF,
llvm::AtomicOrdering AO, const Expr *X,
const Expr *V, const Expr *R,
const Expr *E, const Expr *D,
const Expr *CE, bool IsXBinopExpr,
bool IsPostfixUpdate, bool IsFailOnly,
SourceLocation Loc) {
static void emitOMPAtomicCompareExpr(
CodeGenFunction &CGF, llvm::AtomicOrdering AO, llvm::AtomicOrdering FailAO,
const Expr *X, const Expr *V, const Expr *R, const Expr *E, const Expr *D,
const Expr *CE, bool IsXBinopExpr, bool IsPostfixUpdate, bool IsFailOnly,
SourceLocation Loc) {
llvm::OpenMPIRBuilder &OMPBuilder =
CGF.CGM.getOpenMPRuntime().getOMPBuilder();
@ -6477,13 +6475,21 @@ static void emitOMPAtomicCompareExpr(CodeGenFunction &CGF,
R->getType().isVolatileQualified()};
}
CGF.Builder.restoreIP(OMPBuilder.createAtomicCompare(
CGF.Builder, XOpVal, VOpVal, ROpVal, EVal, DVal, AO, Op, IsXBinopExpr,
IsPostfixUpdate, IsFailOnly));
if (FailAO == llvm::AtomicOrdering::NotAtomic) {
// fail clause was not mentionend on the
// "#pragma omp atomic compare" construct.
CGF.Builder.restoreIP(OMPBuilder.createAtomicCompare(
CGF.Builder, XOpVal, VOpVal, ROpVal, EVal, DVal, AO, Op, IsXBinopExpr,
IsPostfixUpdate, IsFailOnly));
} else
CGF.Builder.restoreIP(OMPBuilder.createAtomicCompare(
CGF.Builder, XOpVal, VOpVal, ROpVal, EVal, DVal, AO, Op, IsXBinopExpr,
IsPostfixUpdate, IsFailOnly, FailAO));
}
static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
llvm::AtomicOrdering AO, bool IsPostfixUpdate,
llvm::AtomicOrdering AO,
llvm::AtomicOrdering FailAO, bool IsPostfixUpdate,
const Expr *X, const Expr *V, const Expr *R,
const Expr *E, const Expr *UE, const Expr *D,
const Expr *CE, bool IsXLHSInRHSPart,
@ -6504,12 +6510,8 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
IsXLHSInRHSPart, Loc);
break;
case OMPC_compare: {
emitOMPAtomicCompareExpr(CGF, AO, X, V, R, E, D, CE, IsXLHSInRHSPart,
IsPostfixUpdate, IsFailOnly, Loc);
break;
}
case OMPC_fail: {
//TODO
emitOMPAtomicCompareExpr(CGF, AO, FailAO, X, V, R, E, D, CE,
IsXLHSInRHSPart, IsPostfixUpdate, IsFailOnly, Loc);
break;
}
default:
@ -6519,6 +6521,8 @@ static void emitOMPAtomicExpr(CodeGenFunction &CGF, OpenMPClauseKind Kind,
void CodeGenFunction::EmitOMPAtomicDirective(const OMPAtomicDirective &S) {
llvm::AtomicOrdering AO = llvm::AtomicOrdering::Monotonic;
// Fail Memory Clause Ordering.
llvm::AtomicOrdering FailAO = llvm::AtomicOrdering::NotAtomic;
bool MemOrderingSpecified = false;
if (S.getSingleClause<OMPSeqCstClause>()) {
AO = llvm::AtomicOrdering::SequentiallyConsistent;
@ -6572,12 +6576,27 @@ void CodeGenFunction::EmitOMPAtomicDirective(const OMPAtomicDirective &S) {
}
}
if (KindsEncountered.contains(OMPC_compare) &&
KindsEncountered.contains(OMPC_fail)) {
Kind = OMPC_compare;
const auto *FailClause = S.getSingleClause<OMPFailClause>();
if (FailClause) {
OpenMPClauseKind FailParameter = FailClause->getFailParameter();
if (FailParameter == llvm::omp::OMPC_relaxed)
FailAO = llvm::AtomicOrdering::Monotonic;
else if (FailParameter == llvm::omp::OMPC_acquire)
FailAO = llvm::AtomicOrdering::Acquire;
else if (FailParameter == llvm::omp::OMPC_seq_cst)
FailAO = llvm::AtomicOrdering::SequentiallyConsistent;
}
}
LexicalScope Scope(*this, S.getSourceRange());
EmitStopPoint(S.getAssociatedStmt());
emitOMPAtomicExpr(*this, Kind, AO, S.isPostfixUpdate(), S.getX(), S.getV(),
S.getR(), S.getExpr(), S.getUpdateExpr(), S.getD(),
S.getCondExpr(), S.isXLHSInRHSPart(), S.isFailOnly(),
S.getBeginLoc());
emitOMPAtomicExpr(*this, Kind, AO, FailAO, S.isPostfixUpdate(), S.getX(),
S.getV(), S.getR(), S.getExpr(), S.getUpdateExpr(),
S.getD(), S.getCondExpr(), S.isXLHSInRHSPart(),
S.isFailOnly(), S.getBeginLoc());
}
static void emitCommonOMPTargetDirective(CodeGenFunction &CGF,

View File

@ -1139,8 +1139,7 @@ CodeGenAction::loadModule(MemoryBufferRef MBRef) {
// Strip off a leading diagnostic code if there is one.
StringRef Msg = Err.getMessage();
if (Msg.starts_with("error: "))
Msg = Msg.substr(7);
Msg.consume_front("error: ");
unsigned DiagID =
CI.getDiagnostics().getCustomDiagID(DiagnosticsEngine::Error, "%0");

View File

@ -324,13 +324,6 @@ ABIArgInfo LoongArchABIInfo::classifyArgumentType(QualType Ty, bool IsFixed,
return ABIArgInfo::getDirect();
}
// Pass 128-bit/256-bit vector values via vector registers directly.
if (Ty->isVectorType() && (((getContext().getTypeSize(Ty) == 128) &&
(getTarget().hasFeature("lsx"))) ||
((getContext().getTypeSize(Ty) == 256) &&
getTarget().hasFeature("lasx"))))
return ABIArgInfo::getDirect();
// Complex types for the *f or *d ABI must be passed directly rather than
// using CoerceAndExpand.
if (IsFixed && Ty->isComplexType() && FRLen && FARsLeft >= 2) {

View File

@ -86,6 +86,7 @@
#include "llvm/Support/PrettyStackTrace.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/Program.h"
#include "llvm/Support/RISCVISAInfo.h"
#include "llvm/Support/StringSaver.h"
#include "llvm/Support/VirtualFileSystem.h"
#include "llvm/Support/raw_ostream.h"
@ -670,10 +671,15 @@ static llvm::Triple computeTargetTriple(const Driver &D,
if (Args.hasArg(options::OPT_march_EQ) ||
Args.hasArg(options::OPT_mcpu_EQ)) {
StringRef ArchName = tools::riscv::getRISCVArch(Args, Target);
if (ArchName.starts_with_insensitive("rv32"))
Target.setArch(llvm::Triple::riscv32);
else if (ArchName.starts_with_insensitive("rv64"))
Target.setArch(llvm::Triple::riscv64);
auto ISAInfo = llvm::RISCVISAInfo::parseArchString(
ArchName, /*EnableExperimentalExtensions=*/true);
if (!llvm::errorToBool(ISAInfo.takeError())) {
unsigned XLen = (*ISAInfo)->getXLen();
if (XLen == 32)
Target.setArch(llvm::Triple::riscv32);
else if (XLen == 64)
Target.setArch(llvm::Triple::riscv64);
}
}
}

View File

@ -168,13 +168,6 @@ void riscv::getRISCVTargetFeatures(const Driver &D, const llvm::Triple &Triple,
Features.push_back("-relax");
}
// GCC Compatibility: -mno-save-restore is default, unless -msave-restore is
// specified.
if (Args.hasFlag(options::OPT_msave_restore, options::OPT_mno_save_restore, false))
Features.push_back("+save-restore");
else
Features.push_back("-save-restore");
// -mno-unaligned-access is default, unless -munaligned-access is specified.
AddTargetFeature(Args, Features, options::OPT_munaligned_access,
options::OPT_mno_unaligned_access, "fast-unaligned-access");
@ -223,10 +216,8 @@ StringRef riscv::getRISCVABI(const ArgList &Args, const llvm::Triple &Triple) {
auto ParseResult = llvm::RISCVISAInfo::parseArchString(
Arch, /* EnableExperimentalExtension */ true);
if (!ParseResult)
// Ignore parsing error, just go 3rd step.
consumeError(ParseResult.takeError());
else
// Ignore parsing error, just go 3rd step.
if (!llvm::errorToBool(ParseResult.takeError()))
return (*ParseResult)->computeDefaultABI();
// 3. Choose a default based on the triple

View File

@ -237,9 +237,7 @@ void x86::getX86TargetFeatures(const Driver &D, const llvm::Triple &Triple,
assert(Name.starts_with("m") && "Invalid feature name.");
Name = Name.substr(1);
bool IsNegative = Name.starts_with("no-");
if (IsNegative)
Name = Name.substr(3);
bool IsNegative = Name.consume_front("no-");
#ifndef NDEBUG
assert(Name.starts_with("avx10.") && "Invalid AVX10 feature name.");

View File

@ -2072,12 +2072,9 @@ void Clang::AddRISCVTargetArgs(const ArgList &Args,
StringRef Arch = riscv::getRISCVArch(Args, Triple);
auto ISAInfo = llvm::RISCVISAInfo::parseArchString(
Arch, /*EnableExperimentalExtensions*/ true);
if (!ISAInfo) {
// Ignore parsing error.
consumeError(ISAInfo.takeError());
} else {
// Ignore parsing error.
if (!errorToBool(ISAInfo.takeError()))
MinVLen = (*ISAInfo)->getMinVLen();
}
// If the value is "zvl", use MinVLen from march. Otherwise, try to parse
// as integer as long as we have a MinVLen.

View File

@ -1133,6 +1133,16 @@ static bool isWholeArchivePresent(const ArgList &Args) {
return WholeArchiveActive;
}
/// Determine if driver is invoked to create a shared object library (-static)
static bool isSharedLinkage(const ArgList &Args) {
return Args.hasArg(options::OPT_shared);
}
/// Determine if driver is invoked to create a static object library (-shared)
static bool isStaticLinkage(const ArgList &Args) {
return Args.hasArg(options::OPT_static);
}
/// Add Fortran runtime libs for MSVC
static void addFortranRuntimeLibsMSVC(const ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) {
@ -1164,6 +1174,16 @@ static void addFortranRuntimeLibsMSVC(const ArgList &Args,
// Add FortranMain runtime lib
static void addFortranMain(const ToolChain &TC, const ArgList &Args,
llvm::opt::ArgStringList &CmdArgs) {
// 0. Shared-library linkage
// If we are attempting to link a library, we should not add
// -lFortran_main.a to the link line, as the `main` symbol is not
// required for a library and should also be provided by one of
// the translation units of the code that this shared library
// will be linked against eventually.
if (isSharedLinkage(Args) || isStaticLinkage(Args)) {
return;
}
// 1. MSVC
if (TC.getTriple().isKnownWindowsMSVCEnvironment()) {
addFortranRuntimeLibsMSVC(Args, CmdArgs);
@ -2368,8 +2388,7 @@ static void GetSDLFromOffloadArchive(
FoundAOB = true;
}
} else {
if (Lib.starts_with("-l"))
Lib = Lib.drop_front(2);
Lib.consume_front("-l");
for (auto LPath : LibraryPaths) {
ArchiveOfBundles.clear();
auto LibFile = (Lib.starts_with(":") ? Lib.drop_front()

View File

@ -1741,11 +1741,9 @@ selectRISCVMultilib(const MultilibSet &RISCVMultilibSet, StringRef Arch,
llvm::RISCVISAInfo::parseArchString(
Arch, /*EnableExperimentalExtension=*/true,
/*ExperimentalExtensionVersionCheck=*/false);
if (!ParseResult) {
// Ignore any error here, we assume it will be handled in another place.
consumeError(ParseResult.takeError());
// Ignore any error here, we assume it will be handled in another place.
if (llvm::errorToBool(ParseResult.takeError()))
return false;
}
auto &ISAInfo = *ParseResult;
@ -1780,10 +1778,8 @@ selectRISCVMultilib(const MultilibSet &RISCVMultilibSet, StringRef Arch,
llvm::RISCVISAInfo::parseArchString(
Flag, /*EnableExperimentalExtension=*/true,
/*ExperimentalExtensionVersionCheck=*/false);
if (!MLConfigParseResult) {
// Ignore any error here, we assume it will handled in another place.
llvm::consumeError(MLConfigParseResult.takeError());
// Ignore any error here, we assume it will handled in another place.
if (llvm::errorToBool(MLConfigParseResult.takeError())) {
// We might get a parsing error if rv32e in the list, we could just skip
// that and process the rest of multi-lib configs.
Skip = true;

View File

@ -295,13 +295,12 @@ static StringRef getSolarisLibSuffix(const llvm::Triple &Triple) {
switch (Triple.getArch()) {
case llvm::Triple::x86:
case llvm::Triple::sparc:
default:
break;
case llvm::Triple::x86_64:
return "/amd64";
case llvm::Triple::sparcv9:
return "/sparcv9";
default:
llvm_unreachable("Unsupported architecture");
}
return "";
}

View File

@ -398,7 +398,7 @@ bool ContinuationIndenter::mustBreak(const LineState &State) {
}
if ((startsNextParameter(Current, Style) || Previous.is(tok::semi) ||
(Previous.is(TT_TemplateCloser) && Current.is(TT_StartOfName) &&
Style.isCpp() &&
State.Line->First->isNot(TT_AttributeSquare) && Style.isCpp() &&
// FIXME: This is a temporary workaround for the case where clang-format
// sets BreakBeforeParameter to avoid bin packing and this creates a
// completely unnecessary line break after a template type that isn't

View File

@ -19,8 +19,8 @@ using namespace llvm;
namespace clang {
namespace format {
// Check whether `FilePath` matches `Pattern` based on POSIX (1003.1-2008)
// 2.13.1, 2.13.2, and Rule 1 of 2.13.3.
// Check whether `FilePath` matches `Pattern` based on POSIX 2.13.1, 2.13.2, and
// Rule 1 of 2.13.3.
bool matchFilePath(StringRef Pattern, StringRef FilePath) {
assert(!Pattern.empty());
assert(!FilePath.empty());

View File

@ -110,8 +110,7 @@ void DependencyGraphCallback::OutputGraphFile() {
writeNodeReference(OS, AllFiles[I]);
OS << " [ shape=\"box\", label=\"";
StringRef FileName = AllFiles[I].getName();
if (FileName.starts_with(SysRoot))
FileName = FileName.substr(SysRoot.size());
FileName.consume_front(SysRoot);
OS << DOT::EscapeString(std::string(FileName)) << "\"];\n";
}

View File

@ -147,8 +147,7 @@ LayoutOverrideSource::LayoutOverrideSource(StringRef Filename) {
// Skip over this offset, the following comma, and any spaces.
LineStr = LineStr.substr(1);
while (!LineStr.empty() && isWhitespace(LineStr[0]))
LineStr = LineStr.substr(1);
LineStr = LineStr.drop_while(isWhitespace);
}
}
@ -163,8 +162,7 @@ LayoutOverrideSource::LayoutOverrideSource(StringRef Filename) {
// Skip over this offset, the following comma, and any spaces.
LineStr = LineStr.substr(1);
while (!LineStr.empty() && isWhitespace(LineStr[0]))
LineStr = LineStr.substr(1);
LineStr = LineStr.drop_while(isWhitespace);
}
continue;
}
@ -180,8 +178,7 @@ LayoutOverrideSource::LayoutOverrideSource(StringRef Filename) {
// Skip over this offset, the following comma, and any spaces.
LineStr = LineStr.substr(1);
while (!LineStr.empty() && isWhitespace(LineStr[0]))
LineStr = LineStr.substr(1);
LineStr = LineStr.drop_while(isWhitespace);
}
}
}

View File

@ -1144,8 +1144,7 @@ std::unique_ptr<Directive> Directive::create(bool RegexKind,
std::string RegexStr;
StringRef S = Text;
while (!S.empty()) {
if (S.starts_with("{{")) {
S = S.drop_front(2);
if (S.consume_front("{{")) {
size_t RegexMatchLength = S.find("}}");
assert(RegexMatchLength != StringRef::npos);
// Append the regex, enclosed in parentheses.

View File

@ -14,12 +14,33 @@
#define __USERMSRINTRIN_H
#ifdef __x86_64__
/// Reads the contents of a 64-bit MSR specified in \a __A into \a dst.
///
/// This intrinsic corresponds to the <c> URDMSR </c> instruction.
/// \param __A
/// An unsigned long long.
///
/// \code{.operation}
/// DEST := MSR[__A]
/// \endcode
static __inline__ unsigned long long
__attribute__((__always_inline__, __nodebug__, __target__("usermsr")))
_urdmsr(unsigned long long __A) {
return __builtin_ia32_urdmsr(__A);
}
/// Writes the contents of \a __B into the 64-bit MSR specified in \a __A.
///
/// This intrinsic corresponds to the <c> UWRMSR </c> instruction.
///
/// \param __A
/// An unsigned long long.
/// \param __B
/// An unsigned long long.
///
/// \code{.operation}
/// MSR[__A] := __B
/// \endcode
static __inline__ void
__attribute__((__always_inline__, __nodebug__, __target__("usermsr")))
_uwrmsr(unsigned long long __A, unsigned long long __B) {

View File

@ -1219,8 +1219,8 @@ void Sema::checkFortifiedBuiltinMemoryFunction(FunctionDecl *FD,
if (IsChkVariant) {
FunctionName = FunctionName.drop_front(std::strlen("__builtin___"));
FunctionName = FunctionName.drop_back(std::strlen("_chk"));
} else if (FunctionName.starts_with("__builtin_")) {
FunctionName = FunctionName.drop_front(std::strlen("__builtin_"));
} else {
FunctionName.consume_front("__builtin_");
}
return FunctionName;
};
@ -5388,15 +5388,17 @@ bool Sema::CheckRISCVBuiltinFunctionCall(const TargetInfo &TI,
QualType Op1Type = TheCall->getArg(0)->getType();
QualType Op2Type = TheCall->getArg(1)->getType();
QualType Op3Type = TheCall->getArg(2)->getType();
uint64_t ElemSize = Op1Type->isRVVType(32, false) ? 32 : 64;
ASTContext::BuiltinVectorTypeInfo Info =
Context.getBuiltinVectorTypeInfo(Op1Type->castAs<BuiltinType>());
uint64_t ElemSize = Context.getTypeSize(Info.ElementType);
if (ElemSize == 64 && !TI.hasFeature("zvknhb"))
return Diag(TheCall->getBeginLoc(),
diag::err_riscv_type_requires_extension)
<< Op1Type << "zvknhb";
diag::err_riscv_builtin_requires_extension)
<< /* IsExtension */ true << TheCall->getSourceRange() << "zvknb";
return CheckInvalidVLENandLMUL(TI, TheCall, *this, Op1Type, ElemSize << 2) ||
CheckInvalidVLENandLMUL(TI, TheCall, *this, Op2Type, ElemSize << 2) ||
CheckInvalidVLENandLMUL(TI, TheCall, *this, Op3Type, ElemSize << 2);
return CheckInvalidVLENandLMUL(TI, TheCall, *this, Op1Type, ElemSize * 4) ||
CheckInvalidVLENandLMUL(TI, TheCall, *this, Op2Type, ElemSize * 4) ||
CheckInvalidVLENandLMUL(TI, TheCall, *this, Op3Type, ElemSize * 4);
}
case RISCVVector::BI__builtin_rvv_sf_vc_i_se_u8mf8:
@ -6170,30 +6172,33 @@ bool Sema::CheckWebAssemblyBuiltinFunctionCall(const TargetInfo &TI,
void Sema::checkRVVTypeSupport(QualType Ty, SourceLocation Loc, Decl *D) {
const TargetInfo &TI = Context.getTargetInfo();
ASTContext::BuiltinVectorTypeInfo Info =
Context.getBuiltinVectorTypeInfo(Ty->castAs<BuiltinType>());
unsigned EltSize = Context.getTypeSize(Info.ElementType);
unsigned MinElts = Info.EC.getKnownMinValue();
// (ELEN, LMUL) pairs of (8, mf8), (16, mf4), (32, mf2), (64, m1) requires at
// least zve64x
if ((Ty->isRVVType(/* Bitwidth */ 64, /* IsFloat */ false) ||
Ty->isRVVType(/* ElementCount */ 1)) &&
if (((EltSize == 64 && Info.ElementType->isIntegerType()) || MinElts == 1) &&
!TI.hasFeature("zve64x"))
Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve64x";
if (Ty->isRVVType(/* Bitwidth */ 16, /* IsFloat */ true) &&
!TI.hasFeature("zvfh") && !TI.hasFeature("zvfhmin"))
else if (Info.ElementType->isFloat16Type() && !TI.hasFeature("zvfh") &&
!TI.hasFeature("zvfhmin"))
Diag(Loc, diag::err_riscv_type_requires_extension, D)
<< Ty << "zvfh or zvfhmin";
// Check if enabled zvfbfmin for BFloat16
if (Ty->isRVVType(/* Bitwidth */ 16, /* IsFloat */ false,
/* IsBFloat */ true) &&
!TI.hasFeature("experimental-zvfbfmin"))
else if (Info.ElementType->isBFloat16Type() &&
!TI.hasFeature("experimental-zvfbfmin"))
Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zvfbfmin";
if (Ty->isRVVType(/* Bitwidth */ 32, /* IsFloat */ true) &&
!TI.hasFeature("zve32f"))
else if (Info.ElementType->isSpecificBuiltinType(BuiltinType::Float) &&
!TI.hasFeature("zve32f"))
Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve32f";
if (Ty->isRVVType(/* Bitwidth */ 64, /* IsFloat */ true) &&
!TI.hasFeature("zve64d"))
else if (Info.ElementType->isSpecificBuiltinType(BuiltinType::Double) &&
!TI.hasFeature("zve64d"))
Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve64d";
// Given that caller already checked isRVVType() before calling this function,
// if we don't have at least zve32x supported, then we need to emit error.
if (!TI.hasFeature("zve32x"))
else if (!TI.hasFeature("zve32x"))
Diag(Loc, diag::err_riscv_type_requires_extension, D) << Ty << "zve32x";
}

View File

@ -5825,8 +5825,7 @@ struct IntrinToName {
static bool ArmBuiltinAliasValid(unsigned BuiltinID, StringRef AliasName,
ArrayRef<IntrinToName> Map,
const char *IntrinNames) {
if (AliasName.starts_with("__arm_"))
AliasName = AliasName.substr(6);
AliasName.consume_front("__arm_");
const IntrinToName *It =
llvm::lower_bound(Map, BuiltinID, [](const IntrinToName &L, unsigned Id) {
return L.Id < Id;

View File

@ -5512,6 +5512,14 @@ static void TryOrBuildParenListInitialization(
} else if (auto *RT = Entity.getType()->getAs<RecordType>()) {
bool IsUnion = RT->isUnionType();
const CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
if (RD->isInvalidDecl()) {
// Exit early to avoid confusion when processing members.
// We do the same for braced list initialization in
// `CheckStructUnionTypes`.
Sequence.SetFailed(
clang::InitializationSequence::FK_ParenthesizedListInitFailed);
return;
}
if (!IsUnion) {
for (const CXXBaseSpecifier &Base : RD->bases()) {

View File

@ -529,7 +529,8 @@ DeclResult Sema::ActOnModuleImport(SourceLocation StartLoc,
if (!Mod)
return true;
if (!Mod->isInterfaceOrPartition() && !ModuleName.empty()) {
if (!Mod->isInterfaceOrPartition() && !ModuleName.empty() &&
!getLangOpts().ObjC) {
Diag(ImportLoc, diag::err_module_import_non_interface_nor_parition)
<< ModuleName;
return true;

View File

@ -12683,7 +12683,7 @@ StmtResult Sema::ActOnOpenMPAtomicDirective(ArrayRef<OMPClause *> Clauses,
break;
}
case OMPC_fail: {
if (AtomicKind != OMPC_compare) {
if (!EncounteredAtomicKinds.contains(OMPC_compare)) {
Diag(C->getBeginLoc(), diag::err_omp_atomic_fail_no_compare)
<< SourceRange(C->getBeginLoc(), C->getEndLoc());
return StmtError();

View File

@ -1706,10 +1706,10 @@ void ASTDeclReader::VisitImplicitParamDecl(ImplicitParamDecl *PD) {
void ASTDeclReader::VisitParmVarDecl(ParmVarDecl *PD) {
VisitVarDecl(PD);
unsigned scopeIndex = Record.readInt();
BitsUnpacker ParmVarDeclBits(Record.readInt());
unsigned isObjCMethodParam = ParmVarDeclBits.getNextBit();
unsigned scopeDepth = ParmVarDeclBits.getNextBits(/*Width=*/7);
unsigned scopeIndex = ParmVarDeclBits.getNextBits(/*Width=*/8);
unsigned declQualifier = ParmVarDeclBits.getNextBits(/*Width=*/7);
if (isObjCMethodParam) {
assert(scopeDepth == 0);

View File

@ -1163,10 +1163,14 @@ void ASTDeclWriter::VisitImplicitParamDecl(ImplicitParamDecl *D) {
void ASTDeclWriter::VisitParmVarDecl(ParmVarDecl *D) {
VisitVarDecl(D);
// See the implementation of `ParmVarDecl::getParameterIndex()`, which may
// exceed the size of the normal bitfield. So it may be better to not pack
// these bits.
Record.push_back(D->getFunctionScopeIndex());
BitsPacker ParmVarDeclBits;
ParmVarDeclBits.addBit(D->isObjCMethodParameter());
ParmVarDeclBits.addBits(D->getFunctionScopeDepth(), /*BitsWidth=*/7);
ParmVarDeclBits.addBits(D->getFunctionScopeIndex(), /*BitsWidth=*/8);
// FIXME: stable encoding
ParmVarDeclBits.addBits(D->getObjCDeclQualifier(), /*BitsWidth=*/7);
ParmVarDeclBits.addBit(D->isKNRPromoted());
@ -2350,10 +2354,11 @@ void ASTWriter::WriteDeclAbbrevs() {
// isARCPseudoStrong, Linkage, ModulesCodegen
Abv->Add(BitCodeAbbrevOp(0)); // VarKind (local enum)
// ParmVarDecl
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::VBR, 6)); // ScopeIndex
Abv->Add(BitCodeAbbrevOp(
BitCodeAbbrevOp::Fixed,
27)); // Packed Parm Var Decl bits: IsObjCMethodParameter, ScopeDepth,
// ScopeIndex, ObjCDeclQualifier, KNRPromoted,
19)); // Packed Parm Var Decl bits: IsObjCMethodParameter, ScopeDepth,
// ObjCDeclQualifier, KNRPromoted,
// HasInheritedDefaultArg, HasUninstantiatedDefaultArg
// Type Source Info
Abv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array));

View File

@ -25,7 +25,7 @@ using namespace ento;
namespace {
class ArrayBoundChecker :
public Checker<check::Location> {
mutable std::unique_ptr<BugType> BT;
const BugType BT{this, "Out-of-bound array access"};
public:
void checkLocation(SVal l, bool isLoad, const Stmt* S,
@ -65,16 +65,13 @@ void ArrayBoundChecker::checkLocation(SVal l, bool isLoad, const Stmt* LoadS,
if (!N)
return;
if (!BT)
BT.reset(new BugType(this, "Out-of-bound array access"));
// FIXME: It would be nice to eventually make this diagnostic more clear,
// e.g., by referencing the original declaration or by saying *why* this
// reference is outside the range.
// Generate a report for this bug.
auto report = std::make_unique<PathSensitiveBugReport>(
*BT, "Access out-of-bound array element (buffer overflow)", N);
BT, "Access out-of-bound array element (buffer overflow)", N);
report->addRange(LoadS->getSourceRange());
C.emitReport(std::move(report));

View File

@ -44,7 +44,7 @@ namespace {
class APIMisuse : public BugType {
public:
APIMisuse(const CheckerBase *checker, const char *name)
: BugType(checker, name, "API Misuse (Apple)") {}
: BugType(checker, name, categories::AppleAPIMisuse) {}
};
} // end anonymous namespace

View File

@ -25,20 +25,31 @@ using namespace clang;
using namespace ento;
namespace {
class BlockInCriticalSectionChecker : public Checker<check::PostCall> {
mutable IdentifierInfo *IILockGuard = nullptr;
mutable IdentifierInfo *IIUniqueLock = nullptr;
mutable bool IdentifierInfoInitialized = false;
mutable IdentifierInfo *IILockGuard, *IIUniqueLock;
const CallDescription LockFn{{"lock"}};
const CallDescription UnlockFn{{"unlock"}};
const CallDescription SleepFn{{"sleep"}};
const CallDescription GetcFn{{"getc"}};
const CallDescription FgetsFn{{"fgets"}};
const CallDescription ReadFn{{"read"}};
const CallDescription RecvFn{{"recv"}};
const CallDescription PthreadLockFn{{"pthread_mutex_lock"}};
const CallDescription PthreadTryLockFn{{"pthread_mutex_trylock"}};
const CallDescription PthreadUnlockFn{{"pthread_mutex_unlock"}};
const CallDescription MtxLock{{"mtx_lock"}};
const CallDescription MtxTimedLock{{"mtx_timedlock"}};
const CallDescription MtxTryLock{{"mtx_trylock"}};
const CallDescription MtxUnlock{{"mtx_unlock"}};
CallDescription LockFn, UnlockFn, SleepFn, GetcFn, FgetsFn, ReadFn, RecvFn,
PthreadLockFn, PthreadTryLockFn, PthreadUnlockFn,
MtxLock, MtxTimedLock, MtxTryLock, MtxUnlock;
const llvm::StringLiteral ClassLockGuard{"lock_guard"};
const llvm::StringLiteral ClassUniqueLock{"unique_lock"};
StringRef ClassLockGuard, ClassUniqueLock;
mutable bool IdentifierInfoInitialized;
std::unique_ptr<BugType> BlockInCritSectionBugType;
const BugType BlockInCritSectionBugType{
this, "Call to blocking function in critical section", "Blocking Error"};
void initIdentifierInfo(ASTContext &Ctx) const;
@ -47,8 +58,6 @@ class BlockInCriticalSectionChecker : public Checker<check::PostCall> {
CheckerContext &C) const;
public:
BlockInCriticalSectionChecker();
bool isBlockingFunction(const CallEvent &Call) const;
bool isLockFunction(const CallEvent &Call) const;
bool isUnlockFunction(const CallEvent &Call) const;
@ -63,22 +72,6 @@ class BlockInCriticalSectionChecker : public Checker<check::PostCall> {
REGISTER_TRAIT_WITH_PROGRAMSTATE(MutexCounter, unsigned)
BlockInCriticalSectionChecker::BlockInCriticalSectionChecker()
: IILockGuard(nullptr), IIUniqueLock(nullptr), LockFn({"lock"}),
UnlockFn({"unlock"}), SleepFn({"sleep"}), GetcFn({"getc"}),
FgetsFn({"fgets"}), ReadFn({"read"}), RecvFn({"recv"}),
PthreadLockFn({"pthread_mutex_lock"}),
PthreadTryLockFn({"pthread_mutex_trylock"}),
PthreadUnlockFn({"pthread_mutex_unlock"}), MtxLock({"mtx_lock"}),
MtxTimedLock({"mtx_timedlock"}), MtxTryLock({"mtx_trylock"}),
MtxUnlock({"mtx_unlock"}), ClassLockGuard("lock_guard"),
ClassUniqueLock("unique_lock"), IdentifierInfoInitialized(false) {
// Initialize the bug type.
BlockInCritSectionBugType.reset(
new BugType(this, "Call to blocking function in critical section",
"Blocking Error"));
}
void BlockInCriticalSectionChecker::initIdentifierInfo(ASTContext &Ctx) const {
if (!IdentifierInfoInitialized) {
/* In case of checking C code, or when the corresponding headers are not
@ -151,7 +144,7 @@ void BlockInCriticalSectionChecker::reportBlockInCritSection(
llvm::raw_string_ostream os(msg);
os << "Call to blocking function '" << Call.getCalleeIdentifier()->getName()
<< "' inside of critical section";
auto R = std::make_unique<PathSensitiveBugReport>(*BlockInCritSectionBugType,
auto R = std::make_unique<PathSensitiveBugReport>(BlockInCritSectionBugType,
os.str(), ErrNode);
R->addRange(Call.getSourceRange());
R->markInteresting(BlockDescSym);

View File

@ -24,7 +24,7 @@ using namespace ento;
namespace {
class BoolAssignmentChecker : public Checker< check::Bind > {
mutable std::unique_ptr<BugType> BT;
const BugType BT{this, "Assignment of a non-Boolean value"};
void emitReport(ProgramStateRef state, CheckerContext &C,
bool IsTainted = false) const;
@ -36,12 +36,9 @@ namespace {
void BoolAssignmentChecker::emitReport(ProgramStateRef state, CheckerContext &C,
bool IsTainted) const {
if (ExplodedNode *N = C.generateNonFatalErrorNode(state)) {
if (!BT)
BT.reset(new BugType(this, "Assignment of a non-Boolean value"));
StringRef Msg = IsTainted ? "Might assign a tainted non-Boolean value"
: "Assignment of a non-Boolean value";
C.emitReport(std::make_unique<PathSensitiveBugReport>(*BT, Msg, N));
C.emitReport(std::make_unique<PathSensitiveBugReport>(BT, Msg, N));
}
}

View File

@ -121,7 +121,7 @@ class CStringChecker : public Checker< eval::Call,
const CallEvent *Call) const;
using FnCheck = std::function<void(const CStringChecker *, CheckerContext &,
const CallExpr *)>;
const CallEvent &)>;
CallDescriptionMap<FnCheck> Callbacks = {
{{CDF_MaybeBuiltin, {"memcpy"}, 3},
@ -173,56 +173,53 @@ class CStringChecker : public Checker< eval::Call,
StdCopyBackward{{"std", "copy_backward"}, 3};
FnCheck identifyCall(const CallEvent &Call, CheckerContext &C) const;
void evalMemcpy(CheckerContext &C, const CallExpr *CE, CharKind CK) const;
void evalMempcpy(CheckerContext &C, const CallExpr *CE, CharKind CK) const;
void evalMemmove(CheckerContext &C, const CallExpr *CE, CharKind CK) const;
void evalBcopy(CheckerContext &C, const CallExpr *CE) const;
void evalCopyCommon(CheckerContext &C, const CallExpr *CE,
void evalMemcpy(CheckerContext &C, const CallEvent &Call, CharKind CK) const;
void evalMempcpy(CheckerContext &C, const CallEvent &Call, CharKind CK) const;
void evalMemmove(CheckerContext &C, const CallEvent &Call, CharKind CK) const;
void evalBcopy(CheckerContext &C, const CallEvent &Call) const;
void evalCopyCommon(CheckerContext &C, const CallEvent &Call,
ProgramStateRef state, SizeArgExpr Size,
DestinationArgExpr Dest, SourceArgExpr Source,
bool Restricted, bool IsMempcpy, CharKind CK) const;
void evalMemcmp(CheckerContext &C, const CallExpr *CE, CharKind CK) const;
void evalMemcmp(CheckerContext &C, const CallEvent &Call, CharKind CK) const;
void evalstrLength(CheckerContext &C, const CallExpr *CE) const;
void evalstrnLength(CheckerContext &C, const CallExpr *CE) const;
void evalstrLengthCommon(CheckerContext &C,
const CallExpr *CE,
void evalstrLength(CheckerContext &C, const CallEvent &Call) const;
void evalstrnLength(CheckerContext &C, const CallEvent &Call) const;
void evalstrLengthCommon(CheckerContext &C, const CallEvent &Call,
bool IsStrnlen = false) const;
void evalStrcpy(CheckerContext &C, const CallExpr *CE) const;
void evalStrncpy(CheckerContext &C, const CallExpr *CE) const;
void evalStpcpy(CheckerContext &C, const CallExpr *CE) const;
void evalStrlcpy(CheckerContext &C, const CallExpr *CE) const;
void evalStrcpyCommon(CheckerContext &C, const CallExpr *CE, bool ReturnEnd,
bool IsBounded, ConcatFnKind appendK,
void evalStrcpy(CheckerContext &C, const CallEvent &Call) const;
void evalStrncpy(CheckerContext &C, const CallEvent &Call) const;
void evalStpcpy(CheckerContext &C, const CallEvent &Call) const;
void evalStrlcpy(CheckerContext &C, const CallEvent &Call) const;
void evalStrcpyCommon(CheckerContext &C, const CallEvent &Call,
bool ReturnEnd, bool IsBounded, ConcatFnKind appendK,
bool returnPtr = true) const;
void evalStrcat(CheckerContext &C, const CallExpr *CE) const;
void evalStrncat(CheckerContext &C, const CallExpr *CE) const;
void evalStrlcat(CheckerContext &C, const CallExpr *CE) const;
void evalStrcat(CheckerContext &C, const CallEvent &Call) const;
void evalStrncat(CheckerContext &C, const CallEvent &Call) const;
void evalStrlcat(CheckerContext &C, const CallEvent &Call) const;
void evalStrcmp(CheckerContext &C, const CallExpr *CE) const;
void evalStrncmp(CheckerContext &C, const CallExpr *CE) const;
void evalStrcasecmp(CheckerContext &C, const CallExpr *CE) const;
void evalStrncasecmp(CheckerContext &C, const CallExpr *CE) const;
void evalStrcmpCommon(CheckerContext &C,
const CallExpr *CE,
bool IsBounded = false,
bool IgnoreCase = false) const;
void evalStrcmp(CheckerContext &C, const CallEvent &Call) const;
void evalStrncmp(CheckerContext &C, const CallEvent &Call) const;
void evalStrcasecmp(CheckerContext &C, const CallEvent &Call) const;
void evalStrncasecmp(CheckerContext &C, const CallEvent &Call) const;
void evalStrcmpCommon(CheckerContext &C, const CallEvent &Call,
bool IsBounded = false, bool IgnoreCase = false) const;
void evalStrsep(CheckerContext &C, const CallExpr *CE) const;
void evalStrsep(CheckerContext &C, const CallEvent &Call) const;
void evalStdCopy(CheckerContext &C, const CallExpr *CE) const;
void evalStdCopyBackward(CheckerContext &C, const CallExpr *CE) const;
void evalStdCopyCommon(CheckerContext &C, const CallExpr *CE) const;
void evalMemset(CheckerContext &C, const CallExpr *CE) const;
void evalBzero(CheckerContext &C, const CallExpr *CE) const;
void evalStdCopy(CheckerContext &C, const CallEvent &Call) const;
void evalStdCopyBackward(CheckerContext &C, const CallEvent &Call) const;
void evalStdCopyCommon(CheckerContext &C, const CallEvent &Call) const;
void evalMemset(CheckerContext &C, const CallEvent &Call) const;
void evalBzero(CheckerContext &C, const CallEvent &Call) const;
void evalSprintf(CheckerContext &C, const CallExpr *CE) const;
void evalSnprintf(CheckerContext &C, const CallExpr *CE) const;
void evalSprintfCommon(CheckerContext &C, const CallExpr *CE, bool IsBounded,
bool IsBuiltin) const;
void evalSprintf(CheckerContext &C, const CallEvent &Call) const;
void evalSnprintf(CheckerContext &C, const CallEvent &Call) const;
void evalSprintfCommon(CheckerContext &C, const CallEvent &Call,
bool IsBounded, bool IsBuiltin) const;
// Utility methods
std::pair<ProgramStateRef , ProgramStateRef >
@ -1291,7 +1288,7 @@ bool CStringChecker::memsetAux(const Expr *DstBuffer, SVal CharVal,
// evaluation of individual function calls.
//===----------------------------------------------------------------------===//
void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
void CStringChecker::evalCopyCommon(CheckerContext &C, const CallEvent &Call,
ProgramStateRef state, SizeArgExpr Size,
DestinationArgExpr Dest,
SourceArgExpr Source, bool Restricted,
@ -1313,7 +1310,8 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
// If the size is zero, there won't be any actual memory access, so
// just bind the return value to the destination buffer and return.
if (stateZeroSize && !stateNonZeroSize) {
stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, destVal);
stateZeroSize =
stateZeroSize->BindExpr(Call.getOriginExpr(), LCtx, destVal);
C.addTransition(stateZeroSize);
return;
}
@ -1361,15 +1359,15 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
// If we don't know how much we copied, we can at least
// conjure a return value for later.
if (lastElement.isUnknown())
lastElement = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx,
C.blockCount());
lastElement = C.getSValBuilder().conjureSymbolVal(
nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
// The byte after the last byte copied is the return value.
state = state->BindExpr(CE, LCtx, lastElement);
state = state->BindExpr(Call.getOriginExpr(), LCtx, lastElement);
} else {
// All other copies return the destination buffer.
// (Well, bcopy() has a void return type, but this won't hurt.)
state = state->BindExpr(CE, LCtx, destVal);
state = state->BindExpr(Call.getOriginExpr(), LCtx, destVal);
}
// Invalidate the destination (regular invalidation without pointer-escaping
@ -1391,69 +1389,69 @@ void CStringChecker::evalCopyCommon(CheckerContext &C, const CallExpr *CE,
}
}
void CStringChecker::evalMemcpy(CheckerContext &C, const CallExpr *CE,
void CStringChecker::evalMemcpy(CheckerContext &C, const CallEvent &Call,
CharKind CK) const {
// void *memcpy(void *restrict dst, const void *restrict src, size_t n);
// The return value is the address of the destination buffer.
DestinationArgExpr Dest = {{CE->getArg(0), 0}};
SourceArgExpr Src = {{CE->getArg(1), 1}};
SizeArgExpr Size = {{CE->getArg(2), 2}};
DestinationArgExpr Dest = {{Call.getArgExpr(0), 0}};
SourceArgExpr Src = {{Call.getArgExpr(1), 1}};
SizeArgExpr Size = {{Call.getArgExpr(2), 2}};
ProgramStateRef State = C.getState();
constexpr bool IsRestricted = true;
constexpr bool IsMempcpy = false;
evalCopyCommon(C, CE, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
evalCopyCommon(C, Call, State, Size, Dest, Src, IsRestricted, IsMempcpy, CK);
}
void CStringChecker::evalMempcpy(CheckerContext &C, const CallExpr *CE,
void CStringChecker::evalMempcpy(CheckerContext &C, const CallEvent &Call,
CharKind CK) const {
// void *mempcpy(void *restrict dst, const void *restrict src, size_t n);
// The return value is a pointer to the byte following the last written byte.
DestinationArgExpr Dest = {{CE->getArg(0), 0}};
SourceArgExpr Src = {{CE->getArg(1), 1}};
SizeArgExpr Size = {{CE->getArg(2), 2}};
DestinationArgExpr Dest = {{Call.getArgExpr(0), 0}};
SourceArgExpr Src = {{Call.getArgExpr(1), 1}};
SizeArgExpr Size = {{Call.getArgExpr(2), 2}};
constexpr bool IsRestricted = true;
constexpr bool IsMempcpy = true;
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
CK);
evalCopyCommon(C, Call, C.getState(), Size, Dest, Src, IsRestricted,
IsMempcpy, CK);
}
void CStringChecker::evalMemmove(CheckerContext &C, const CallExpr *CE,
void CStringChecker::evalMemmove(CheckerContext &C, const CallEvent &Call,
CharKind CK) const {
// void *memmove(void *dst, const void *src, size_t n);
// The return value is the address of the destination buffer.
DestinationArgExpr Dest = {{CE->getArg(0), 0}};
SourceArgExpr Src = {{CE->getArg(1), 1}};
SizeArgExpr Size = {{CE->getArg(2), 2}};
DestinationArgExpr Dest = {{Call.getArgExpr(0), 0}};
SourceArgExpr Src = {{Call.getArgExpr(1), 1}};
SizeArgExpr Size = {{Call.getArgExpr(2), 2}};
constexpr bool IsRestricted = false;
constexpr bool IsMempcpy = false;
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
CK);
evalCopyCommon(C, Call, C.getState(), Size, Dest, Src, IsRestricted,
IsMempcpy, CK);
}
void CStringChecker::evalBcopy(CheckerContext &C, const CallExpr *CE) const {
void CStringChecker::evalBcopy(CheckerContext &C, const CallEvent &Call) const {
// void bcopy(const void *src, void *dst, size_t n);
SourceArgExpr Src{{CE->getArg(0), 0}};
DestinationArgExpr Dest = {{CE->getArg(1), 1}};
SizeArgExpr Size = {{CE->getArg(2), 2}};
SourceArgExpr Src{{Call.getArgExpr(0), 0}};
DestinationArgExpr Dest = {{Call.getArgExpr(1), 1}};
SizeArgExpr Size = {{Call.getArgExpr(2), 2}};
constexpr bool IsRestricted = false;
constexpr bool IsMempcpy = false;
evalCopyCommon(C, CE, C.getState(), Size, Dest, Src, IsRestricted, IsMempcpy,
CharKind::Regular);
evalCopyCommon(C, Call, C.getState(), Size, Dest, Src, IsRestricted,
IsMempcpy, CharKind::Regular);
}
void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE,
void CStringChecker::evalMemcmp(CheckerContext &C, const CallEvent &Call,
CharKind CK) const {
// int memcmp(const void *s1, const void *s2, size_t n);
CurrentFunctionDescription = "memory comparison function";
AnyArgExpr Left = {CE->getArg(0), 0};
AnyArgExpr Right = {CE->getArg(1), 1};
SizeArgExpr Size = {{CE->getArg(2), 2}};
AnyArgExpr Left = {Call.getArgExpr(0), 0};
AnyArgExpr Right = {Call.getArgExpr(1), 1};
SizeArgExpr Size = {{Call.getArgExpr(2), 2}};
ProgramStateRef State = C.getState();
SValBuilder &Builder = C.getSValBuilder();
@ -1471,7 +1469,8 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE,
// have to check either of the buffers.
if (stateZeroSize) {
State = stateZeroSize;
State = State->BindExpr(CE, LCtx, Builder.makeZeroVal(CE->getType()));
State = State->BindExpr(Call.getOriginExpr(), LCtx,
Builder.makeZeroVal(Call.getResultType()));
C.addTransition(State);
}
@ -1497,8 +1496,8 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE,
State = SameBuffer;
State = CheckBufferAccess(C, State, Left, Size, AccessKind::read);
if (State) {
State =
SameBuffer->BindExpr(CE, LCtx, Builder.makeZeroVal(CE->getType()));
State = SameBuffer->BindExpr(Call.getOriginExpr(), LCtx,
Builder.makeZeroVal(Call.getResultType()));
C.addTransition(State);
}
return;
@ -1511,33 +1510,35 @@ void CStringChecker::evalMemcmp(CheckerContext &C, const CallExpr *CE,
State = CheckBufferAccess(C, State, Left, Size, AccessKind::read, CK);
if (State) {
// The return value is the comparison result, which we don't know.
SVal CmpV = Builder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
State = State->BindExpr(CE, LCtx, CmpV);
SVal CmpV = Builder.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx,
C.blockCount());
State = State->BindExpr(Call.getOriginExpr(), LCtx, CmpV);
C.addTransition(State);
}
}
}
void CStringChecker::evalstrLength(CheckerContext &C,
const CallExpr *CE) const {
const CallEvent &Call) const {
// size_t strlen(const char *s);
evalstrLengthCommon(C, CE, /* IsStrnlen = */ false);
evalstrLengthCommon(C, Call, /* IsStrnlen = */ false);
}
void CStringChecker::evalstrnLength(CheckerContext &C,
const CallExpr *CE) const {
const CallEvent &Call) const {
// size_t strnlen(const char *s, size_t maxlen);
evalstrLengthCommon(C, CE, /* IsStrnlen = */ true);
evalstrLengthCommon(C, Call, /* IsStrnlen = */ true);
}
void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
void CStringChecker::evalstrLengthCommon(CheckerContext &C,
const CallEvent &Call,
bool IsStrnlen) const {
CurrentFunctionDescription = "string length function";
ProgramStateRef state = C.getState();
const LocationContext *LCtx = C.getLocationContext();
if (IsStrnlen) {
const Expr *maxlenExpr = CE->getArg(1);
const Expr *maxlenExpr = Call.getArgExpr(1);
SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
ProgramStateRef stateZeroSize, stateNonZeroSize;
@ -1547,8 +1548,8 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
// If the size can be zero, the result will be 0 in that case, and we don't
// have to check the string itself.
if (stateZeroSize) {
SVal zero = C.getSValBuilder().makeZeroVal(CE->getType());
stateZeroSize = stateZeroSize->BindExpr(CE, LCtx, zero);
SVal zero = C.getSValBuilder().makeZeroVal(Call.getResultType());
stateZeroSize = stateZeroSize->BindExpr(Call.getOriginExpr(), LCtx, zero);
C.addTransition(stateZeroSize);
}
@ -1561,7 +1562,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
}
// Check that the string argument is non-null.
AnyArgExpr Arg = {CE->getArg(0), 0};
AnyArgExpr Arg = {Call.getArgExpr(0), 0};
SVal ArgVal = state->getSVal(Arg.Expression, LCtx);
state = checkNonNull(C, state, Arg, ArgVal);
@ -1584,7 +1585,7 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
// It's a little unfortunate to be getting this again,
// but it's not that expensive...
const Expr *maxlenExpr = CE->getArg(1);
const Expr *maxlenExpr = Call.getArgExpr(1);
SVal maxlenVal = state->getSVal(maxlenExpr, LCtx);
std::optional<NonLoc> strLengthNL = strLength.getAs<NonLoc>();
@ -1613,8 +1614,8 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
// no guarantee the full string length will actually be returned.
// All we know is the return value is the min of the string length
// and the limit. This is better than nothing.
result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx,
C.blockCount());
result = C.getSValBuilder().conjureSymbolVal(
nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
NonLoc resultNL = result.castAs<NonLoc>();
if (strLengthNL) {
@ -1637,78 +1638,85 @@ void CStringChecker::evalstrLengthCommon(CheckerContext &C, const CallExpr *CE,
// If we don't know the length of the string, conjure a return
// value, so it can be used in constraints, at least.
if (result.isUnknown()) {
result = C.getSValBuilder().conjureSymbolVal(nullptr, CE, LCtx,
C.blockCount());
result = C.getSValBuilder().conjureSymbolVal(
nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
}
}
// Bind the return value.
assert(!result.isUnknown() && "Should have conjured a value by now");
state = state->BindExpr(CE, LCtx, result);
state = state->BindExpr(Call.getOriginExpr(), LCtx, result);
C.addTransition(state);
}
void CStringChecker::evalStrcpy(CheckerContext &C, const CallExpr *CE) const {
void CStringChecker::evalStrcpy(CheckerContext &C,
const CallEvent &Call) const {
// char *strcpy(char *restrict dst, const char *restrict src);
evalStrcpyCommon(C, CE,
evalStrcpyCommon(C, Call,
/* ReturnEnd = */ false,
/* IsBounded = */ false,
/* appendK = */ ConcatFnKind::none);
}
void CStringChecker::evalStrncpy(CheckerContext &C, const CallExpr *CE) const {
void CStringChecker::evalStrncpy(CheckerContext &C,
const CallEvent &Call) const {
// char *strncpy(char *restrict dst, const char *restrict src, size_t n);
evalStrcpyCommon(C, CE,
evalStrcpyCommon(C, Call,
/* ReturnEnd = */ false,
/* IsBounded = */ true,
/* appendK = */ ConcatFnKind::none);
}
void CStringChecker::evalStpcpy(CheckerContext &C, const CallExpr *CE) const {
void CStringChecker::evalStpcpy(CheckerContext &C,
const CallEvent &Call) const {
// char *stpcpy(char *restrict dst, const char *restrict src);
evalStrcpyCommon(C, CE,
evalStrcpyCommon(C, Call,
/* ReturnEnd = */ true,
/* IsBounded = */ false,
/* appendK = */ ConcatFnKind::none);
}
void CStringChecker::evalStrlcpy(CheckerContext &C, const CallExpr *CE) const {
void CStringChecker::evalStrlcpy(CheckerContext &C,
const CallEvent &Call) const {
// size_t strlcpy(char *dest, const char *src, size_t size);
evalStrcpyCommon(C, CE,
evalStrcpyCommon(C, Call,
/* ReturnEnd = */ true,
/* IsBounded = */ true,
/* appendK = */ ConcatFnKind::none,
/* returnPtr = */ false);
}
void CStringChecker::evalStrcat(CheckerContext &C, const CallExpr *CE) const {
void CStringChecker::evalStrcat(CheckerContext &C,
const CallEvent &Call) const {
// char *strcat(char *restrict s1, const char *restrict s2);
evalStrcpyCommon(C, CE,
evalStrcpyCommon(C, Call,
/* ReturnEnd = */ false,
/* IsBounded = */ false,
/* appendK = */ ConcatFnKind::strcat);
}
void CStringChecker::evalStrncat(CheckerContext &C, const CallExpr *CE) const {
void CStringChecker::evalStrncat(CheckerContext &C,
const CallEvent &Call) const {
// char *strncat(char *restrict s1, const char *restrict s2, size_t n);
evalStrcpyCommon(C, CE,
evalStrcpyCommon(C, Call,
/* ReturnEnd = */ false,
/* IsBounded = */ true,
/* appendK = */ ConcatFnKind::strcat);
}
void CStringChecker::evalStrlcat(CheckerContext &C, const CallExpr *CE) const {
void CStringChecker::evalStrlcat(CheckerContext &C,
const CallEvent &Call) const {
// size_t strlcat(char *dst, const char *src, size_t size);
// It will append at most size - strlen(dst) - 1 bytes,
// NULL-terminating the result.
evalStrcpyCommon(C, CE,
evalStrcpyCommon(C, Call,
/* ReturnEnd = */ false,
/* IsBounded = */ true,
/* appendK = */ ConcatFnKind::strlcat,
/* returnPtr = */ false);
}
void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallEvent &Call,
bool ReturnEnd, bool IsBounded,
ConcatFnKind appendK,
bool returnPtr) const {
@ -1721,14 +1729,14 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
const LocationContext *LCtx = C.getLocationContext();
// Check that the destination is non-null.
DestinationArgExpr Dst = {{CE->getArg(0), 0}};
DestinationArgExpr Dst = {{Call.getArgExpr(0), 0}};
SVal DstVal = state->getSVal(Dst.Expression, LCtx);
state = checkNonNull(C, state, Dst, DstVal);
if (!state)
return;
// Check that the source is non-null.
SourceArgExpr srcExpr = {{CE->getArg(1), 1}};
SourceArgExpr srcExpr = {{Call.getArgExpr(1), 1}};
SVal srcVal = state->getSVal(srcExpr.Expression, LCtx);
state = checkNonNull(C, state, srcExpr, srcVal);
if (!state)
@ -1763,8 +1771,8 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
{srcExpr.Expression, srcExpr.ArgumentIndex}};
state = CheckOverlap(
C, state,
(IsBounded ? SizeArgExpr{{CE->getArg(2), 2}} : SrcExprAsSizeDummy), Dst,
srcExpr);
(IsBounded ? SizeArgExpr{{Call.getArgExpr(2), 2}} : SrcExprAsSizeDummy),
Dst, srcExpr);
if (!state)
return;
@ -1772,7 +1780,7 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// If the function is strncpy, strncat, etc... it is bounded.
if (IsBounded) {
// Get the max number of characters to copy.
SizeArgExpr lenExpr = {{CE->getArg(2), 2}};
SizeArgExpr lenExpr = {{Call.getArgExpr(2), 2}};
SVal lenVal = state->getSVal(lenExpr.Expression, LCtx);
// Protect against misdeclared strncpy().
@ -1886,16 +1894,19 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// If the size is known to be zero, we're done.
if (StateZeroSize && !StateNonZeroSize) {
if (returnPtr) {
StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, DstVal);
StateZeroSize =
StateZeroSize->BindExpr(Call.getOriginExpr(), LCtx, DstVal);
} else {
if (appendK == ConcatFnKind::none) {
// strlcpy returns strlen(src)
StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, strLength);
StateZeroSize = StateZeroSize->BindExpr(Call.getOriginExpr(),
LCtx, strLength);
} else {
// strlcat returns strlen(src) + strlen(dst)
SVal retSize = svalBuilder.evalBinOp(
state, BO_Add, strLength, dstStrLength, sizeTy);
StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, retSize);
StateZeroSize =
StateZeroSize->BindExpr(Call.getOriginExpr(), LCtx, retSize);
}
}
C.addTransition(StateZeroSize);
@ -1964,7 +1975,8 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
if (finalStrLength.isUnknown()) {
// Try to get a "hypothetical" string length symbol, which we can later
// set as a real value if that turns out to be the case.
finalStrLength = getCStringLength(C, state, CE, DstVal, true);
finalStrLength =
getCStringLength(C, state, Call.getOriginExpr(), DstVal, true);
assert(!finalStrLength.isUndef());
if (std::optional<NonLoc> finalStrLengthNL =
@ -2094,51 +2106,54 @@ void CStringChecker::evalStrcpyCommon(CheckerContext &C, const CallExpr *CE,
// If this is a stpcpy-style copy, but we were unable to check for a buffer
// overflow, we still need a result. Conjure a return value.
if (ReturnEnd && Result.isUnknown()) {
Result = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
Result = svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx,
C.blockCount());
}
}
// Set the return value.
state = state->BindExpr(CE, LCtx, Result);
state = state->BindExpr(Call.getOriginExpr(), LCtx, Result);
C.addTransition(state);
}
void CStringChecker::evalStrcmp(CheckerContext &C, const CallExpr *CE) const {
void CStringChecker::evalStrcmp(CheckerContext &C,
const CallEvent &Call) const {
//int strcmp(const char *s1, const char *s2);
evalStrcmpCommon(C, CE, /* IsBounded = */ false, /* IgnoreCase = */ false);
evalStrcmpCommon(C, Call, /* IsBounded = */ false, /* IgnoreCase = */ false);
}
void CStringChecker::evalStrncmp(CheckerContext &C, const CallExpr *CE) const {
void CStringChecker::evalStrncmp(CheckerContext &C,
const CallEvent &Call) const {
//int strncmp(const char *s1, const char *s2, size_t n);
evalStrcmpCommon(C, CE, /* IsBounded = */ true, /* IgnoreCase = */ false);
evalStrcmpCommon(C, Call, /* IsBounded = */ true, /* IgnoreCase = */ false);
}
void CStringChecker::evalStrcasecmp(CheckerContext &C,
const CallExpr *CE) const {
const CallEvent &Call) const {
//int strcasecmp(const char *s1, const char *s2);
evalStrcmpCommon(C, CE, /* IsBounded = */ false, /* IgnoreCase = */ true);
evalStrcmpCommon(C, Call, /* IsBounded = */ false, /* IgnoreCase = */ true);
}
void CStringChecker::evalStrncasecmp(CheckerContext &C,
const CallExpr *CE) const {
const CallEvent &Call) const {
//int strncasecmp(const char *s1, const char *s2, size_t n);
evalStrcmpCommon(C, CE, /* IsBounded = */ true, /* IgnoreCase = */ true);
evalStrcmpCommon(C, Call, /* IsBounded = */ true, /* IgnoreCase = */ true);
}
void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
bool IsBounded, bool IgnoreCase) const {
void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallEvent &Call,
bool IsBounded, bool IgnoreCase) const {
CurrentFunctionDescription = "string comparison function";
ProgramStateRef state = C.getState();
const LocationContext *LCtx = C.getLocationContext();
// Check that the first string is non-null
AnyArgExpr Left = {CE->getArg(0), 0};
AnyArgExpr Left = {Call.getArgExpr(0), 0};
SVal LeftVal = state->getSVal(Left.Expression, LCtx);
state = checkNonNull(C, state, Left, LeftVal);
if (!state)
return;
// Check that the second string is non-null.
AnyArgExpr Right = {CE->getArg(1), 1};
AnyArgExpr Right = {Call.getArgExpr(1), 1};
SVal RightVal = state->getSVal(Right.Expression, LCtx);
state = checkNonNull(C, state, Right, RightVal);
if (!state)
@ -2169,8 +2184,9 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
// If the two arguments might be the same buffer, we know the result is 0,
// and we only need to check one size.
if (StSameBuf) {
StSameBuf = StSameBuf->BindExpr(CE, LCtx,
svalBuilder.makeZeroVal(CE->getType()));
StSameBuf =
StSameBuf->BindExpr(Call.getOriginExpr(), LCtx,
svalBuilder.makeZeroVal(Call.getResultType()));
C.addTransition(StSameBuf);
// If the two arguments are GUARANTEED to be the same, we're done!
@ -2190,8 +2206,8 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
const StringLiteral *RightStrLiteral =
getCStringLiteral(C, state, Right.Expression, RightVal);
bool canComputeResult = false;
SVal resultVal = svalBuilder.conjureSymbolVal(nullptr, CE, LCtx,
C.blockCount());
SVal resultVal = svalBuilder.conjureSymbolVal(nullptr, Call.getOriginExpr(),
LCtx, C.blockCount());
if (LeftStrLiteral && RightStrLiteral) {
StringRef LeftStrRef = LeftStrLiteral->getString();
@ -2199,7 +2215,7 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
if (IsBounded) {
// Get the max number of characters to compare.
const Expr *lenExpr = CE->getArg(2);
const Expr *lenExpr = Call.getArgExpr(2);
SVal lenVal = state->getSVal(lenExpr, LCtx);
// If the length is known, we can get the right substrings.
@ -2231,10 +2247,10 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
// The strcmp function returns an integer greater than, equal to, or less
// than zero, [c11, p7.24.4.2].
if (compareRes == 0) {
resultVal = svalBuilder.makeIntVal(compareRes, CE->getType());
resultVal = svalBuilder.makeIntVal(compareRes, Call.getResultType());
}
else {
DefinedSVal zeroVal = svalBuilder.makeIntVal(0, CE->getType());
DefinedSVal zeroVal = svalBuilder.makeIntVal(0, Call.getResultType());
// Constrain strcmp's result range based on the result of StringRef's
// comparison methods.
BinaryOperatorKind op = (compareRes > 0) ? BO_GT : BO_LT;
@ -2247,20 +2263,21 @@ void CStringChecker::evalStrcmpCommon(CheckerContext &C, const CallExpr *CE,
}
}
state = state->BindExpr(CE, LCtx, resultVal);
state = state->BindExpr(Call.getOriginExpr(), LCtx, resultVal);
// Record this as a possible path.
C.addTransition(state);
}
void CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const {
void CStringChecker::evalStrsep(CheckerContext &C,
const CallEvent &Call) const {
// char *strsep(char **stringp, const char *delim);
// Verify whether the search string parameter matches the return type.
SourceArgExpr SearchStrPtr = {{CE->getArg(0), 0}};
SourceArgExpr SearchStrPtr = {{Call.getArgExpr(0), 0}};
QualType CharPtrTy = SearchStrPtr.Expression->getType()->getPointeeType();
if (CharPtrTy.isNull() ||
CE->getType().getUnqualifiedType() != CharPtrTy.getUnqualifiedType())
if (CharPtrTy.isNull() || Call.getResultType().getUnqualifiedType() !=
CharPtrTy.getUnqualifiedType())
return;
CurrentFunctionDescription = "strsep()";
@ -2275,7 +2292,7 @@ void CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const {
return;
// Check that the delimiter string is non-null.
AnyArgExpr DelimStr = {CE->getArg(1), 1};
AnyArgExpr DelimStr = {Call.getArgExpr(1), 1};
SVal DelimStrVal = State->getSVal(DelimStr.Expression, LCtx);
State = checkNonNull(C, State, DelimStr, DelimStrVal);
if (!State)
@ -2295,37 +2312,37 @@ void CStringChecker::evalStrsep(CheckerContext &C, const CallExpr *CE) const {
// Overwrite the search string pointer. The new value is either an address
// further along in the same string, or NULL if there are no more tokens.
State = State->bindLoc(*SearchStrLoc,
SVB.conjureSymbolVal(getTag(),
CE,
LCtx,
CharPtrTy,
C.blockCount()),
LCtx);
State =
State->bindLoc(*SearchStrLoc,
SVB.conjureSymbolVal(getTag(), Call.getOriginExpr(),
LCtx, CharPtrTy, C.blockCount()),
LCtx);
} else {
assert(SearchStrVal.isUnknown());
// Conjure a symbolic value. It's the best we can do.
Result = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
Result = SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx,
C.blockCount());
}
// Set the return value, and finish.
State = State->BindExpr(CE, LCtx, Result);
State = State->BindExpr(Call.getOriginExpr(), LCtx, Result);
C.addTransition(State);
}
// These should probably be moved into a C++ standard library checker.
void CStringChecker::evalStdCopy(CheckerContext &C, const CallExpr *CE) const {
evalStdCopyCommon(C, CE);
void CStringChecker::evalStdCopy(CheckerContext &C,
const CallEvent &Call) const {
evalStdCopyCommon(C, Call);
}
void CStringChecker::evalStdCopyBackward(CheckerContext &C,
const CallExpr *CE) const {
evalStdCopyCommon(C, CE);
const CallEvent &Call) const {
evalStdCopyCommon(C, Call);
}
void CStringChecker::evalStdCopyCommon(CheckerContext &C,
const CallExpr *CE) const {
if (!CE->getArg(2)->getType()->isPointerType())
const CallEvent &Call) const {
if (!Call.getArgExpr(2)->getType()->isPointerType())
return;
ProgramStateRef State = C.getState();
@ -2338,7 +2355,7 @@ void CStringChecker::evalStdCopyCommon(CheckerContext &C,
// _OutputIterator __result)
// Invalidate the destination buffer
const Expr *Dst = CE->getArg(2);
const Expr *Dst = Call.getArgExpr(2);
SVal DstVal = State->getSVal(Dst, LCtx);
// FIXME: As we do not know how many items are copied, we also invalidate the
// super region containing the target location.
@ -2347,19 +2364,21 @@ void CStringChecker::evalStdCopyCommon(CheckerContext &C,
SValBuilder &SVB = C.getSValBuilder();
SVal ResultVal = SVB.conjureSymbolVal(nullptr, CE, LCtx, C.blockCount());
State = State->BindExpr(CE, LCtx, ResultVal);
SVal ResultVal =
SVB.conjureSymbolVal(nullptr, Call.getOriginExpr(), LCtx, C.blockCount());
State = State->BindExpr(Call.getOriginExpr(), LCtx, ResultVal);
C.addTransition(State);
}
void CStringChecker::evalMemset(CheckerContext &C, const CallExpr *CE) const {
void CStringChecker::evalMemset(CheckerContext &C,
const CallEvent &Call) const {
// void *memset(void *s, int c, size_t n);
CurrentFunctionDescription = "memory set function";
DestinationArgExpr Buffer = {{CE->getArg(0), 0}};
AnyArgExpr CharE = {CE->getArg(1), 1};
SizeArgExpr Size = {{CE->getArg(2), 2}};
DestinationArgExpr Buffer = {{Call.getArgExpr(0), 0}};
AnyArgExpr CharE = {Call.getArgExpr(1), 1};
SizeArgExpr Size = {{Call.getArgExpr(2), 2}};
ProgramStateRef State = C.getState();
@ -2377,7 +2396,7 @@ void CStringChecker::evalMemset(CheckerContext &C, const CallExpr *CE) const {
// If the size is zero, there won't be any actual memory access, so
// just bind the return value to the buffer and return.
if (ZeroSize && !NonZeroSize) {
ZeroSize = ZeroSize->BindExpr(CE, LCtx, BufferPtrVal);
ZeroSize = ZeroSize->BindExpr(Call.getOriginExpr(), LCtx, BufferPtrVal);
C.addTransition(ZeroSize);
return;
}
@ -2399,15 +2418,15 @@ void CStringChecker::evalMemset(CheckerContext &C, const CallExpr *CE) const {
Size.Expression, C, State))
return;
State = State->BindExpr(CE, LCtx, BufferPtrVal);
State = State->BindExpr(Call.getOriginExpr(), LCtx, BufferPtrVal);
C.addTransition(State);
}
void CStringChecker::evalBzero(CheckerContext &C, const CallExpr *CE) const {
void CStringChecker::evalBzero(CheckerContext &C, const CallEvent &Call) const {
CurrentFunctionDescription = "memory clearance function";
DestinationArgExpr Buffer = {{CE->getArg(0), 0}};
SizeArgExpr Size = {{CE->getArg(1), 1}};
DestinationArgExpr Buffer = {{Call.getArgExpr(0), 0}};
SizeArgExpr Size = {{Call.getArgExpr(1), 1}};
SVal Zero = C.getSValBuilder().makeZeroVal(C.getASTContext().IntTy);
ProgramStateRef State = C.getState();
@ -2446,24 +2465,29 @@ void CStringChecker::evalBzero(CheckerContext &C, const CallExpr *CE) const {
C.addTransition(State);
}
void CStringChecker::evalSprintf(CheckerContext &C, const CallExpr *CE) const {
void CStringChecker::evalSprintf(CheckerContext &C,
const CallEvent &Call) const {
CurrentFunctionDescription = "'sprintf'";
const auto *CE = cast<CallExpr>(Call.getOriginExpr());
bool IsBI = CE->getBuiltinCallee() == Builtin::BI__builtin___sprintf_chk;
evalSprintfCommon(C, CE, /* IsBounded */ false, IsBI);
evalSprintfCommon(C, Call, /* IsBounded */ false, IsBI);
}
void CStringChecker::evalSnprintf(CheckerContext &C, const CallExpr *CE) const {
void CStringChecker::evalSnprintf(CheckerContext &C,
const CallEvent &Call) const {
CurrentFunctionDescription = "'snprintf'";
const auto *CE = cast<CallExpr>(Call.getOriginExpr());
bool IsBI = CE->getBuiltinCallee() == Builtin::BI__builtin___snprintf_chk;
evalSprintfCommon(C, CE, /* IsBounded */ true, IsBI);
evalSprintfCommon(C, Call, /* IsBounded */ true, IsBI);
}
void CStringChecker::evalSprintfCommon(CheckerContext &C, const CallExpr *CE,
void CStringChecker::evalSprintfCommon(CheckerContext &C, const CallEvent &Call,
bool IsBounded, bool IsBuiltin) const {
ProgramStateRef State = C.getState();
DestinationArgExpr Dest = {{CE->getArg(0), 0}};
const auto *CE = cast<CallExpr>(Call.getOriginExpr());
DestinationArgExpr Dest = {{Call.getArgExpr(0), 0}};
const auto NumParams = CE->getCalleeDecl()->getAsFunction()->getNumParams();
const auto NumParams = Call.parameters().size();
assert(CE->getNumArgs() >= NumParams);
const auto AllArguments =
@ -2483,7 +2507,7 @@ void CStringChecker::evalSprintfCommon(CheckerContext &C, const CallExpr *CE,
{Source.Expression, Source.ArgumentIndex}};
State = CheckOverlap(
C, State,
(IsBounded ? SizeArgExpr{{CE->getArg(1), 1}} : SrcExprAsSizeDummy),
(IsBounded ? SizeArgExpr{{Call.getArgExpr(1), 1}} : SrcExprAsSizeDummy),
Dest, Source);
if (!State)
return;
@ -2536,8 +2560,8 @@ bool CStringChecker::evalCall(const CallEvent &Call, CheckerContext &C) const {
return false;
// Check and evaluate the call.
const auto *CE = cast<CallExpr>(Call.getOriginExpr());
Callback(this, C, CE);
assert(isa<CallExpr>(Call.getOriginExpr()));
Callback(this, C, Call);
// If the evaluate call resulted in no change, chain to the next eval call
// handler.

View File

@ -31,6 +31,7 @@
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
@ -65,7 +66,8 @@ class CXXDeleteChecker : public Checker<check::PreStmt<CXXDeleteExpr>> {
};
class DeleteWithNonVirtualDtorChecker : public CXXDeleteChecker {
mutable std::unique_ptr<BugType> BT;
const BugType BT{
this, "Destruction of a polymorphic object with no virtual destructor"};
void
checkTypedDeleteExpr(const CXXDeleteExpr *DE, CheckerContext &C,
@ -74,7 +76,8 @@ class DeleteWithNonVirtualDtorChecker : public CXXDeleteChecker {
};
class CXXArrayDeleteChecker : public CXXDeleteChecker {
mutable std::unique_ptr<BugType> BT;
const BugType BT{this,
"Deleting an array of polymorphic objects is undefined"};
void
checkTypedDeleteExpr(const CXXDeleteExpr *DE, CheckerContext &C,
@ -123,17 +126,10 @@ void DeleteWithNonVirtualDtorChecker::checkTypedDeleteExpr(
if (!DerivedClass->isDerivedFrom(BaseClass))
return;
if (!BT)
BT.reset(new BugType(this,
"Destruction of a polymorphic object with no "
"virtual destructor",
"Logic error"));
ExplodedNode *N = C.generateNonFatalErrorNode();
if (!N)
return;
auto R =
std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
auto R = std::make_unique<PathSensitiveBugReport>(BT, BT.getDescription(), N);
// Mark region of problematic base class for later use in the BugVisitor.
R->markInteresting(BaseClassRegion);
@ -160,12 +156,6 @@ void CXXArrayDeleteChecker::checkTypedDeleteExpr(
if (!DerivedClass->isDerivedFrom(BaseClass))
return;
if (!BT)
BT.reset(new BugType(this,
"Deleting an array of polymorphic objects "
"is undefined",
"Logic error"));
ExplodedNode *N = C.generateNonFatalErrorNode();
if (!N)
return;
@ -182,7 +172,7 @@ void CXXArrayDeleteChecker::checkTypedDeleteExpr(
<< SourceType.getAsString(C.getASTContext().getPrintingPolicy())
<< "' is undefined";
auto R = std::make_unique<PathSensitiveBugReport>(*BT, OS.str(), N);
auto R = std::make_unique<PathSensitiveBugReport>(BT, OS.str(), N);
// Mark region of problematic base class for later use in the BugVisitor.
R->markInteresting(BaseClassRegion);

View File

@ -125,9 +125,8 @@ class CallAndMessageChecker
if (!BT)
BT.reset(new BugType(OriginalName, desc));
}
bool uninitRefOrPointer(CheckerContext &C, const SVal &V,
SourceRange ArgRange, const Expr *ArgEx,
std::unique_ptr<BugType> &BT,
bool uninitRefOrPointer(CheckerContext &C, SVal V, SourceRange ArgRange,
const Expr *ArgEx, std::unique_ptr<BugType> &BT,
const ParmVarDecl *ParamDecl, const char *BD,
int ArgumentNumber) const;
};
@ -185,7 +184,7 @@ static void describeUninitializedArgumentInCall(const CallEvent &Call,
}
bool CallAndMessageChecker::uninitRefOrPointer(
CheckerContext &C, const SVal &V, SourceRange ArgRange, const Expr *ArgEx,
CheckerContext &C, SVal V, SourceRange ArgRange, const Expr *ArgEx,
std::unique_ptr<BugType> &BT, const ParmVarDecl *ParamDecl, const char *BD,
int ArgumentNumber) const {
@ -263,7 +262,7 @@ class FindUninitializedField {
if (Find(FR))
return true;
} else {
const SVal &V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
SVal V = StoreMgr.getBinding(store, loc::MemRegionVal(FR));
if (V.isUndef())
return true;
}

View File

@ -24,7 +24,7 @@ using namespace ento;
namespace {
class CastSizeChecker : public Checker< check::PreStmt<CastExpr> > {
mutable std::unique_ptr<BugType> BT;
const BugType BT{this, "Cast region with wrong size."};
public:
void checkPreStmt(const CastExpr *CE, CheckerContext &C) const;
@ -131,12 +131,10 @@ void CastSizeChecker::checkPreStmt(const CastExpr *CE,CheckerContext &C) const {
return;
if (ExplodedNode *errorNode = C.generateErrorNode()) {
if (!BT)
BT.reset(new BugType(this, "Cast region with wrong size."));
constexpr llvm::StringLiteral Msg =
"Cast a region whose size is not a multiple of the destination type "
"size.";
auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, errorNode);
auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, errorNode);
R->addRange(CE->getSourceRange());
C.emitReport(std::move(R));
}

View File

@ -99,18 +99,23 @@ class ObjCDeallocChecker
check::PointerEscape,
check::PreStmt<ReturnStmt>> {
mutable IdentifierInfo *NSObjectII, *SenTestCaseII, *XCTestCaseII,
*Block_releaseII, *CIFilterII;
mutable const IdentifierInfo *NSObjectII = nullptr;
mutable const IdentifierInfo *SenTestCaseII = nullptr;
mutable const IdentifierInfo *XCTestCaseII = nullptr;
mutable const IdentifierInfo *Block_releaseII = nullptr;
mutable const IdentifierInfo *CIFilterII = nullptr;
mutable Selector DeallocSel, ReleaseSel;
mutable Selector DeallocSel;
mutable Selector ReleaseSel;
std::unique_ptr<BugType> MissingReleaseBugType;
std::unique_ptr<BugType> ExtraReleaseBugType;
std::unique_ptr<BugType> MistakenDeallocBugType;
const BugType MissingReleaseBugType{this, "Missing ivar release (leak)",
categories::MemoryRefCount};
const BugType ExtraReleaseBugType{this, "Extra ivar release",
categories::MemoryRefCount};
const BugType MistakenDeallocBugType{this, "Mistaken dealloc",
categories::MemoryRefCount};
public:
ObjCDeallocChecker();
void checkASTDecl(const ObjCImplementationDecl *D, AnalysisManager& Mgr,
BugReporter &BR) const;
void checkBeginFunction(CheckerContext &Ctx) const;
@ -579,7 +584,7 @@ void ObjCDeallocChecker::diagnoseMissingReleases(CheckerContext &C) const {
OS << " by a synthesized property but not released"
" before '[super dealloc]'";
auto BR = std::make_unique<PathSensitiveBugReport>(*MissingReleaseBugType,
auto BR = std::make_unique<PathSensitiveBugReport>(MissingReleaseBugType,
OS.str(), ErrNode);
C.emitReport(std::move(BR));
}
@ -701,7 +706,7 @@ bool ObjCDeallocChecker::diagnoseExtraRelease(SymbolRef ReleasedValue,
OS << " property but was released in 'dealloc'";
}
auto BR = std::make_unique<PathSensitiveBugReport>(*ExtraReleaseBugType,
auto BR = std::make_unique<PathSensitiveBugReport>(ExtraReleaseBugType,
OS.str(), ErrNode);
BR->addRange(M.getOriginExpr()->getSourceRange());
@ -743,7 +748,7 @@ bool ObjCDeallocChecker::diagnoseMistakenDealloc(SymbolRef DeallocedValue,
OS << "'" << *PropImpl->getPropertyIvarDecl()
<< "' should be released rather than deallocated";
auto BR = std::make_unique<PathSensitiveBugReport>(*MistakenDeallocBugType,
auto BR = std::make_unique<PathSensitiveBugReport>(MistakenDeallocBugType,
OS.str(), ErrNode);
BR->addRange(M.getOriginExpr()->getSourceRange());
@ -752,23 +757,6 @@ bool ObjCDeallocChecker::diagnoseMistakenDealloc(SymbolRef DeallocedValue,
return true;
}
ObjCDeallocChecker::ObjCDeallocChecker()
: NSObjectII(nullptr), SenTestCaseII(nullptr), XCTestCaseII(nullptr),
Block_releaseII(nullptr), CIFilterII(nullptr) {
MissingReleaseBugType.reset(
new BugType(this, "Missing ivar release (leak)",
categories::MemoryRefCount));
ExtraReleaseBugType.reset(
new BugType(this, "Extra ivar release",
categories::MemoryRefCount));
MistakenDeallocBugType.reset(
new BugType(this, "Mistaken dealloc",
categories::MemoryRefCount));
}
void ObjCDeallocChecker::initIdentifierInfoAndSelectors(
ASTContext &Ctx) const {
if (NSObjectII)

View File

@ -140,8 +140,7 @@ void WalkAST::VisitCallExpr(CallExpr *CE) {
if (!II) // if no identifier, not a simple C function
return;
StringRef Name = II->getName();
if (Name.starts_with("__builtin_"))
Name = Name.substr(10);
Name.consume_front("__builtin_");
// Set the evaluation function by switching on the callee name.
FnCheck evalFunction =
@ -763,8 +762,7 @@ void WalkAST::checkDeprecatedOrUnsafeBufferHandling(const CallExpr *CE,
enum { DEPR_ONLY = -1, UNKNOWN_CALL = -2 };
StringRef Name = FD->getIdentifier()->getName();
if (Name.starts_with("__builtin_"))
Name = Name.substr(10);
Name.consume_front("__builtin_");
int ArgIndex =
llvm::StringSwitch<int>(Name)

View File

@ -41,7 +41,7 @@ bool isRootChanged(intptr_t k) { return k == ROOT_CHANGED; }
// bug<--foo()-- JAIL_ENTERED<--foo()--
class ChrootChecker : public Checker<eval::Call, check::PreCall> {
// This bug refers to possibly break out of a chroot() jail.
mutable std::unique_ptr<BugType> BT_BreakJail;
const BugType BT_BreakJail{this, "Break out of jail"};
const CallDescription Chroot{{"chroot"}, 1}, Chdir{{"chdir"}, 1};
@ -124,12 +124,10 @@ void ChrootChecker::checkPreCall(const CallEvent &Call,
if (k)
if (isRootChanged((intptr_t) *k))
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
if (!BT_BreakJail)
BT_BreakJail.reset(new BugType(this, "Break out of jail"));
constexpr llvm::StringLiteral Msg =
"No call of chdir(\"/\") immediately after chroot";
C.emitReport(
std::make_unique<PathSensitiveBugReport>(*BT_BreakJail, Msg, N));
std::make_unique<PathSensitiveBugReport>(BT_BreakJail, Msg, N));
}
}

View File

@ -35,7 +35,8 @@ class CloneChecker
private:
mutable CloneDetector Detector;
mutable std::unique_ptr<BugType> BT_Exact, BT_Suspicious;
const BugType BT_Exact{this, "Exact code clone", "Code clone"};
const BugType BT_Suspicious{this, "Suspicious code clone", "Code clone"};
public:
void checkASTCodeBody(const Decl *D, AnalysisManager &Mgr,
@ -107,15 +108,11 @@ static PathDiagnosticLocation makeLocation(const StmtSequence &S,
void CloneChecker::reportClones(
BugReporter &BR, AnalysisManager &Mgr,
std::vector<CloneDetector::CloneGroup> &CloneGroups) const {
if (!BT_Exact)
BT_Exact.reset(new BugType(this, "Exact code clone", "Code clone"));
for (const CloneDetector::CloneGroup &Group : CloneGroups) {
// We group the clones by printing the first as a warning and all others
// as a note.
auto R = std::make_unique<BasicBugReport>(
*BT_Exact, "Duplicate code detected", makeLocation(Group.front(), Mgr));
BT_Exact, "Duplicate code detected", makeLocation(Group.front(), Mgr));
R->addRange(Group.front().getSourceRange());
for (unsigned i = 1; i < Group.size(); ++i)
@ -154,10 +151,6 @@ void CloneChecker::reportSuspiciousClones(
}
}
if (!BT_Suspicious)
BT_Suspicious.reset(
new BugType(this, "Suspicious code clone", "Code clone"));
ASTContext &ACtx = BR.getContext();
SourceManager &SM = ACtx.getSourceManager();
AnalysisDeclContext *ADC =
@ -170,7 +163,7 @@ void CloneChecker::reportSuspiciousClones(
// Think how to perform more accurate suggestions?
auto R = std::make_unique<BasicBugReport>(
*BT_Suspicious,
BT_Suspicious,
"Potential copy-paste error; did you really mean to use '" +
Pair.FirstCloneInfo.Variable->getNameAsString() + "' here?",
PathDiagnosticLocation::createBegin(Pair.FirstCloneInfo.Mention, SM,

View File

@ -42,7 +42,7 @@ class ConversionChecker : public Checker<check::PreStmt<ImplicitCastExpr>> {
void checkPreStmt(const ImplicitCastExpr *Cast, CheckerContext &C) const;
private:
mutable std::unique_ptr<BugType> BT;
const BugType BT{this, "Conversion"};
bool isLossOfPrecision(const ImplicitCastExpr *Cast, QualType DestType,
CheckerContext &C) const;
@ -126,11 +126,8 @@ void ConversionChecker::checkPreStmt(const ImplicitCastExpr *Cast,
void ConversionChecker::reportBug(ExplodedNode *N, const Expr *E,
CheckerContext &C, const char Msg[]) const {
if (!BT)
BT.reset(new BugType(this, "Conversion"));
// Generate a report for this bug.
auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
bugreporter::trackExpressionValue(N, E, *R);
C.emitReport(std::move(R));
}

View File

@ -28,7 +28,8 @@ namespace {
class DebugContainerModeling
: public Checker<eval::Call> {
std::unique_ptr<BugType> DebugMsgBugType;
const BugType DebugMsgBugType{this, "Checking analyzer assumptions", "debug",
/*SuppressOnSink=*/true};
template <typename Getter>
void analyzerContainerDataField(const CallExpr *CE, CheckerContext &C,
@ -48,19 +49,11 @@ class DebugContainerModeling
};
public:
DebugContainerModeling();
bool evalCall(const CallEvent &Call, CheckerContext &C) const;
};
} //namespace
DebugContainerModeling::DebugContainerModeling() {
DebugMsgBugType.reset(
new BugType(this, "Checking analyzer assumptions", "debug",
/*SuppressOnSink=*/true));
}
bool DebugContainerModeling::evalCall(const CallEvent &Call,
CheckerContext &C) const {
const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
@ -137,8 +130,8 @@ ExplodedNode *DebugContainerModeling::reportDebugMsg(llvm::StringRef Msg,
return nullptr;
auto &BR = C.getBugReporter();
BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType,
Msg, N));
BR.emitReport(
std::make_unique<PathSensitiveBugReport>(DebugMsgBugType, Msg, N));
return N;
}

View File

@ -28,7 +28,8 @@ namespace {
class DebugIteratorModeling
: public Checker<eval::Call> {
std::unique_ptr<BugType> DebugMsgBugType;
const BugType DebugMsgBugType{this, "Checking analyzer assumptions", "debug",
/*SuppressOnSink=*/true};
template <typename Getter>
void analyzerIteratorDataField(const CallExpr *CE, CheckerContext &C,
@ -51,19 +52,11 @@ class DebugIteratorModeling
};
public:
DebugIteratorModeling();
bool evalCall(const CallEvent &Call, CheckerContext &C) const;
};
} //namespace
DebugIteratorModeling::DebugIteratorModeling() {
DebugMsgBugType.reset(
new BugType(this, "Checking analyzer assumptions", "debug",
/*SuppressOnSink=*/true));
}
bool DebugIteratorModeling::evalCall(const CallEvent &Call,
CheckerContext &C) const {
const auto *CE = dyn_cast_or_null<CallExpr>(Call.getOriginExpr());
@ -131,8 +124,8 @@ ExplodedNode *DebugIteratorModeling::reportDebugMsg(llvm::StringRef Msg,
return nullptr;
auto &BR = C.getBugReporter();
BR.emitReport(std::make_unique<PathSensitiveBugReport>(*DebugMsgBugType,
Msg, N));
BR.emitReport(
std::make_unique<PathSensitiveBugReport>(DebugMsgBugType, Msg, N));
return N;
}

View File

@ -14,6 +14,7 @@
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Checkers/Taint.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
@ -25,8 +26,8 @@ using namespace taint;
namespace {
class DivZeroChecker : public Checker< check::PreStmt<BinaryOperator> > {
mutable std::unique_ptr<BugType> BT;
mutable std::unique_ptr<BugType> TaintBT;
const BugType BT{this, "Division by zero"};
const BugType TaintBT{this, "Division by zero", categories::TaintedData};
void reportBug(StringRef Msg, ProgramStateRef StateZero,
CheckerContext &C) const;
void reportTaintBug(StringRef Msg, ProgramStateRef StateZero,
@ -48,10 +49,7 @@ static const Expr *getDenomExpr(const ExplodedNode *N) {
void DivZeroChecker::reportBug(StringRef Msg, ProgramStateRef StateZero,
CheckerContext &C) const {
if (ExplodedNode *N = C.generateErrorNode(StateZero)) {
if (!BT)
BT.reset(new BugType(this, "Division by zero", categories::LogicError));
auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
bugreporter::trackExpressionValue(N, getDenomExpr(N), *R);
C.emitReport(std::move(R));
}
@ -61,11 +59,7 @@ void DivZeroChecker::reportTaintBug(
StringRef Msg, ProgramStateRef StateZero, CheckerContext &C,
llvm::ArrayRef<SymbolRef> TaintedSyms) const {
if (ExplodedNode *N = C.generateErrorNode(StateZero)) {
if (!TaintBT)
TaintBT.reset(
new BugType(this, "Division by zero", categories::TaintedData));
auto R = std::make_unique<PathSensitiveBugReport>(*TaintBT, Msg, N);
auto R = std::make_unique<PathSensitiveBugReport>(TaintBT, Msg, N);
bugreporter::trackExpressionValue(N, getDenomExpr(N), *R);
for (auto Sym : TaintedSyms)
R->markInteresting(Sym);

View File

@ -30,12 +30,7 @@ using namespace ento;
namespace {
class DynamicTypeChecker : public Checker<check::PostStmt<ImplicitCastExpr>> {
mutable std::unique_ptr<BugType> BT;
void initBugType() const {
if (!BT)
BT.reset(
new BugType(this, "Dynamic and static type mismatch", "Type Error"));
}
const BugType BT{this, "Dynamic and static type mismatch", "Type Error"};
class DynamicTypeBugVisitor : public BugReporterVisitor {
public:
@ -70,7 +65,6 @@ void DynamicTypeChecker::reportTypeError(QualType DynamicType,
const MemRegion *Reg,
const Stmt *ReportedNode,
CheckerContext &C) const {
initBugType();
SmallString<192> Buf;
llvm::raw_svector_ostream OS(Buf);
OS << "Object has a dynamic type '";
@ -81,7 +75,7 @@ void DynamicTypeChecker::reportTypeError(QualType DynamicType,
llvm::Twine());
OS << "'";
auto R = std::make_unique<PathSensitiveBugReport>(
*BT, OS.str(), C.generateNonFatalErrorNode());
BT, OS.str(), C.generateNonFatalErrorNode());
R->markInteresting(Reg);
R->addVisitor(std::make_unique<DynamicTypeBugVisitor>(Reg));
R->addRange(ReportedNode->getSourceRange());

View File

@ -60,7 +60,7 @@ class ConstraintBasedEQEvaluator {
// Being conservative, it does not warn if there is slight possibility the
// value can be matching.
class EnumCastOutOfRangeChecker : public Checker<check::PreStmt<CastExpr>> {
mutable std::unique_ptr<BugType> EnumValueCastOutOfRange;
const BugType EnumValueCastOutOfRange{this, "Enum cast out of range"};
void reportWarning(CheckerContext &C, const CastExpr *CE,
const EnumDecl *E) const;
@ -85,10 +85,6 @@ void EnumCastOutOfRangeChecker::reportWarning(CheckerContext &C,
const EnumDecl *E) const {
assert(E && "valid EnumDecl* is expected");
if (const ExplodedNode *N = C.generateNonFatalErrorNode()) {
if (!EnumValueCastOutOfRange)
EnumValueCastOutOfRange.reset(
new BugType(this, "Enum cast out of range"));
std::string ValueStr = "", NameStr = "the enum";
// Try to add details to the message:
@ -105,7 +101,7 @@ void EnumCastOutOfRangeChecker::reportWarning(CheckerContext &C,
"not in the valid range of values for {1}",
ValueStr, NameStr);
auto BR = std::make_unique<PathSensitiveBugReport>(*EnumValueCastOutOfRange,
auto BR = std::make_unique<PathSensitiveBugReport>(EnumValueCastOutOfRange,
Msg, N);
bugreporter::trackExpressionValue(N, CE->getSubExpr(), *BR);
BR->addNote("enum declared here",

View File

@ -25,7 +25,7 @@ using namespace ento;
namespace {
class ExprInspectionChecker
: public Checker<eval::Call, check::DeadSymbols, check::EndAnalysis> {
mutable std::unique_ptr<BugType> BT;
const BugType BT{this, "Checking analyzer assumptions", "debug"};
// These stats are per-analysis, not per-branch, hence they shouldn't
// stay inside the program state.
@ -176,11 +176,7 @@ ExprInspectionChecker::reportBug(llvm::StringRef Msg, BugReporter &BR,
std::optional<SVal> ExprVal) const {
if (!N)
return nullptr;
if (!BT)
BT.reset(new BugType(this, "Checking analyzer assumptions", "debug"));
auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
if (ExprVal) {
R->markInteresting(*ExprVal);
}

View File

@ -24,7 +24,7 @@ using namespace ento;
namespace {
class FixedAddressChecker
: public Checker< check::PreStmt<BinaryOperator> > {
mutable std::unique_ptr<BugType> BT;
const BugType BT{this, "Use fixed address"};
public:
void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
@ -50,12 +50,10 @@ void FixedAddressChecker::checkPreStmt(const BinaryOperator *B,
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
// FIXME: improve grammar in the following strings:
if (!BT)
BT.reset(new BugType(this, "Use fixed address"));
constexpr llvm::StringLiteral Msg =
"Using a fixed address is not portable because that address will "
"probably not be valid in all environments or platforms.";
auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
R->addRange(B->getRHS()->getSourceRange());
C.emitReport(std::move(R));
}

View File

@ -31,14 +31,14 @@ class InvalidatedIteratorChecker
check::PreStmt<ArraySubscriptExpr>,
check::PreStmt<MemberExpr>> {
std::unique_ptr<BugType> InvalidatedBugType;
const BugType InvalidatedBugType{this, "Iterator invalidated",
"Misuse of STL APIs"};
void verifyAccess(CheckerContext &C, SVal Val) const;
void reportBug(StringRef Message, SVal Val, CheckerContext &C,
ExplodedNode *ErrNode) const;
void verifyAccess(CheckerContext &C, const SVal &Val) const;
void reportBug(const StringRef &Message, const SVal &Val,
CheckerContext &C, ExplodedNode *ErrNode) const;
public:
InvalidatedIteratorChecker();
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
void checkPreStmt(const UnaryOperator *UO, CheckerContext &C) const;
void checkPreStmt(const BinaryOperator *BO, CheckerContext &C) const;
@ -49,11 +49,6 @@ class InvalidatedIteratorChecker
} //namespace
InvalidatedIteratorChecker::InvalidatedIteratorChecker() {
InvalidatedBugType.reset(
new BugType(this, "Iterator invalidated", "Misuse of STL APIs"));
}
void InvalidatedIteratorChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
// Check for access of invalidated position
@ -114,7 +109,8 @@ void InvalidatedIteratorChecker::checkPreStmt(const MemberExpr *ME,
verifyAccess(C, BaseVal);
}
void InvalidatedIteratorChecker::verifyAccess(CheckerContext &C, const SVal &Val) const {
void InvalidatedIteratorChecker::verifyAccess(CheckerContext &C,
SVal Val) const {
auto State = C.getState();
const auto *Pos = getIteratorPosition(State, Val);
if (Pos && !Pos->isValid()) {
@ -126,11 +122,11 @@ void InvalidatedIteratorChecker::verifyAccess(CheckerContext &C, const SVal &Val
}
}
void InvalidatedIteratorChecker::reportBug(const StringRef &Message,
const SVal &Val, CheckerContext &C,
void InvalidatedIteratorChecker::reportBug(StringRef Message, SVal Val,
CheckerContext &C,
ExplodedNode *ErrNode) const {
auto R = std::make_unique<PathSensitiveBugReport>(*InvalidatedBugType,
Message, ErrNode);
auto R = std::make_unique<PathSensitiveBugReport>(InvalidatedBugType, Message,
ErrNode);
R->markInteresting(Val);
C.emitReport(std::move(R));
}

View File

@ -181,8 +181,7 @@ const ContainerData *getContainerData(ProgramStateRef State,
return State->get<ContainerMap>(Cont);
}
const IteratorPosition *getIteratorPosition(ProgramStateRef State,
const SVal &Val) {
const IteratorPosition *getIteratorPosition(ProgramStateRef State, SVal Val) {
if (auto Reg = Val.getAsRegion()) {
Reg = Reg->getMostDerivedObjectRegion();
return State->get<IteratorRegionMap>(Reg);
@ -194,7 +193,7 @@ const IteratorPosition *getIteratorPosition(ProgramStateRef State,
return nullptr;
}
ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
ProgramStateRef setIteratorPosition(ProgramStateRef State, SVal Val,
const IteratorPosition &Pos) {
if (auto Reg = Val.getAsRegion()) {
Reg = Reg->getMostDerivedObjectRegion();
@ -207,8 +206,8 @@ ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
return nullptr;
}
ProgramStateRef createIteratorPosition(ProgramStateRef State, const SVal &Val,
const MemRegion *Cont, const Stmt* S,
ProgramStateRef createIteratorPosition(ProgramStateRef State, SVal Val,
const MemRegion *Cont, const Stmt *S,
const LocationContext *LCtx,
unsigned blockCount) {
auto &StateMgr = State->getStateManager();
@ -221,9 +220,8 @@ ProgramStateRef createIteratorPosition(ProgramStateRef State, const SVal &Val,
IteratorPosition::getPosition(Cont, Sym));
}
ProgramStateRef advancePosition(ProgramStateRef State, const SVal &Iter,
OverloadedOperatorKind Op,
const SVal &Distance) {
ProgramStateRef advancePosition(ProgramStateRef State, SVal Iter,
OverloadedOperatorKind Op, SVal Distance) {
const auto *Pos = getIteratorPosition(State, Iter);
if (!Pos)
return nullptr;

View File

@ -161,18 +161,15 @@ bool isRandomIncrOrDecrOperator(OverloadedOperatorKind OK);
bool isRandomIncrOrDecrOperator(BinaryOperatorKind OK);
const ContainerData *getContainerData(ProgramStateRef State,
const MemRegion *Cont);
const IteratorPosition *getIteratorPosition(ProgramStateRef State,
const SVal &Val);
ProgramStateRef setIteratorPosition(ProgramStateRef State, const SVal &Val,
const IteratorPosition *getIteratorPosition(ProgramStateRef State, SVal Val);
ProgramStateRef setIteratorPosition(ProgramStateRef State, SVal Val,
const IteratorPosition &Pos);
ProgramStateRef createIteratorPosition(ProgramStateRef State, const SVal &Val,
const MemRegion *Cont, const Stmt* S,
ProgramStateRef createIteratorPosition(ProgramStateRef State, SVal Val,
const MemRegion *Cont, const Stmt *S,
const LocationContext *LCtx,
unsigned blockCount);
ProgramStateRef advancePosition(ProgramStateRef State,
const SVal &Iter,
OverloadedOperatorKind Op,
const SVal &Distance);
ProgramStateRef advancePosition(ProgramStateRef State, SVal Iter,
OverloadedOperatorKind Op, SVal Distance);
ProgramStateRef assumeNoOverflow(ProgramStateRef State, SymbolRef Sym,
long Scale);
bool compare(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2,

View File

@ -100,18 +100,17 @@ class IteratorModeling
const AdvanceFn *Handler) const;
void handleComparison(CheckerContext &C, const Expr *CE, SVal RetVal,
const SVal &LVal, const SVal &RVal,
OverloadedOperatorKind Op) const;
SVal LVal, SVal RVal, OverloadedOperatorKind Op) const;
void processComparison(CheckerContext &C, ProgramStateRef State,
SymbolRef Sym1, SymbolRef Sym2, const SVal &RetVal,
SymbolRef Sym1, SymbolRef Sym2, SVal RetVal,
OverloadedOperatorKind Op) const;
void handleIncrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
void handleIncrement(CheckerContext &C, SVal RetVal, SVal Iter,
bool Postfix) const;
void handleDecrement(CheckerContext &C, const SVal &RetVal, const SVal &Iter,
void handleDecrement(CheckerContext &C, SVal RetVal, SVal Iter,
bool Postfix) const;
void handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE,
OverloadedOperatorKind Op, const SVal &RetVal,
const SVal &Iterator, const SVal &Amount) const;
OverloadedOperatorKind Op, SVal RetVal,
SVal Iterator, SVal Amount) const;
void handlePtrIncrOrDecr(CheckerContext &C, const Expr *Iterator,
OverloadedOperatorKind OK, SVal Offset) const;
void handleAdvance(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter,
@ -120,7 +119,7 @@ class IteratorModeling
SVal Amount) const;
void handleNext(CheckerContext &C, const Expr *CE, SVal RetVal, SVal Iter,
SVal Amount) const;
void assignToContainer(CheckerContext &C, const Expr *CE, const SVal &RetVal,
void assignToContainer(CheckerContext &C, const Expr *CE, SVal RetVal,
const MemRegion *Cont) const;
bool noChangeInAdvance(CheckerContext &C, SVal Iter, const Expr *CE) const;
void printState(raw_ostream &Out, ProgramStateRef State, const char *NL,
@ -160,7 +159,7 @@ class IteratorModeling
bool isSimpleComparisonOperator(OverloadedOperatorKind OK);
bool isSimpleComparisonOperator(BinaryOperatorKind OK);
ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val);
ProgramStateRef removeIteratorPosition(ProgramStateRef State, SVal Val);
ProgramStateRef relateSymbols(ProgramStateRef State, SymbolRef Sym1,
SymbolRef Sym2, bool Equal);
bool isBoundThroughLazyCompoundVal(const Environment &Env,
@ -283,7 +282,7 @@ void IteratorModeling::checkPostStmt(const BinaryOperator *BO,
// The non-iterator side must have an integral or enumeration type.
if (!AmountExpr->getType()->isIntegralOrEnumerationType())
return;
const SVal &AmountVal = IsIterOnLHS ? RVal : LVal;
SVal AmountVal = IsIterOnLHS ? RVal : LVal;
handlePtrIncrOrDecr(C, IterExpr, BinaryOperator::getOverloadedOperator(OK),
AmountVal);
}
@ -388,8 +387,8 @@ IteratorModeling::handleOverloadedOperator(CheckerContext &C,
const bool IsIterFirst = FirstType->isStructureOrClassType();
const SVal FirstArg = Call.getArgSVal(0);
const SVal SecondArg = Call.getArgSVal(1);
const SVal &Iterator = IsIterFirst ? FirstArg : SecondArg;
const SVal &Amount = IsIterFirst ? SecondArg : FirstArg;
SVal Iterator = IsIterFirst ? FirstArg : SecondArg;
SVal Amount = IsIterFirst ? SecondArg : FirstArg;
handleRandomIncrOrDecr(C, OrigExpr, Op, Call.getReturnValue(),
Iterator, Amount);
@ -444,14 +443,13 @@ IteratorModeling::handleAdvanceLikeFunction(CheckerContext &C,
}
void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE,
SVal RetVal, const SVal &LVal,
const SVal &RVal,
OverloadedOperatorKind Op) const {
SVal RetVal, SVal LVal, SVal RVal,
OverloadedOperatorKind Op) const {
// Record the operands and the operator of the comparison for the next
// evalAssume, if the result is a symbolic expression. If it is a concrete
// value (only one branch is possible), then transfer the state between
// the operands according to the operator and the result
auto State = C.getState();
auto State = C.getState();
const auto *LPos = getIteratorPosition(State, LVal);
const auto *RPos = getIteratorPosition(State, RVal);
const MemRegion *Cont = nullptr;
@ -504,7 +502,7 @@ void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE,
void IteratorModeling::processComparison(CheckerContext &C,
ProgramStateRef State, SymbolRef Sym1,
SymbolRef Sym2, const SVal &RetVal,
SymbolRef Sym2, SVal RetVal,
OverloadedOperatorKind Op) const {
if (const auto TruthVal = RetVal.getAs<nonloc::ConcreteInt>()) {
if ((State = relateSymbols(State, Sym1, Sym2,
@ -532,8 +530,8 @@ void IteratorModeling::processComparison(CheckerContext &C,
}
}
void IteratorModeling::handleIncrement(CheckerContext &C, const SVal &RetVal,
const SVal &Iter, bool Postfix) const {
void IteratorModeling::handleIncrement(CheckerContext &C, SVal RetVal,
SVal Iter, bool Postfix) const {
// Increment the symbolic expressions which represents the position of the
// iterator
auto State = C.getState();
@ -558,8 +556,8 @@ void IteratorModeling::handleIncrement(CheckerContext &C, const SVal &RetVal,
C.addTransition(State);
}
void IteratorModeling::handleDecrement(CheckerContext &C, const SVal &RetVal,
const SVal &Iter, bool Postfix) const {
void IteratorModeling::handleDecrement(CheckerContext &C, SVal RetVal,
SVal Iter, bool Postfix) const {
// Decrement the symbolic expressions which represents the position of the
// iterator
auto State = C.getState();
@ -586,9 +584,8 @@ void IteratorModeling::handleDecrement(CheckerContext &C, const SVal &RetVal,
void IteratorModeling::handleRandomIncrOrDecr(CheckerContext &C, const Expr *CE,
OverloadedOperatorKind Op,
const SVal &RetVal,
const SVal &Iterator,
const SVal &Amount) const {
SVal RetVal, SVal Iterator,
SVal Amount) const {
// Increment or decrement the symbolic expressions which represents the
// position of the iterator
auto State = C.getState();
@ -684,7 +681,7 @@ void IteratorModeling::handleNext(CheckerContext &C, const Expr *CE,
}
void IteratorModeling::assignToContainer(CheckerContext &C, const Expr *CE,
const SVal &RetVal,
SVal RetVal,
const MemRegion *Cont) const {
Cont = Cont->getMostDerivedObjectRegion();
@ -772,7 +769,7 @@ bool isSimpleComparisonOperator(BinaryOperatorKind OK) {
return OK == BO_EQ || OK == BO_NE;
}
ProgramStateRef removeIteratorPosition(ProgramStateRef State, const SVal &Val) {
ProgramStateRef removeIteratorPosition(ProgramStateRef State, SVal Val) {
if (auto Reg = Val.getAsRegion()) {
Reg = Reg->getMostDerivedObjectRegion();
return State->remove<IteratorRegionMap>(Reg);

View File

@ -32,7 +32,8 @@ class IteratorRangeChecker
check::PreStmt<ArraySubscriptExpr>,
check::PreStmt<MemberExpr>> {
std::unique_ptr<BugType> OutOfRangeBugType;
const BugType OutOfRangeBugType{this, "Iterator out of range",
"Misuse of STL APIs"};
void verifyDereference(CheckerContext &C, SVal Val) const;
void verifyIncrement(CheckerContext &C, SVal Iter) const;
@ -42,12 +43,10 @@ class IteratorRangeChecker
void verifyAdvance(CheckerContext &C, SVal LHS, SVal RHS) const;
void verifyPrev(CheckerContext &C, SVal LHS, SVal RHS) const;
void verifyNext(CheckerContext &C, SVal LHS, SVal RHS) const;
void reportBug(const StringRef &Message, SVal Val, CheckerContext &C,
void reportBug(StringRef Message, SVal Val, CheckerContext &C,
ExplodedNode *ErrNode) const;
public:
IteratorRangeChecker();
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
void checkPreStmt(const UnaryOperator *UO, CheckerContext &C) const;
void checkPreStmt(const BinaryOperator *BO, CheckerContext &C) const;
@ -67,15 +66,10 @@ class IteratorRangeChecker
bool isPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
bool isAheadOfRange(ProgramStateRef State, const IteratorPosition &Pos);
bool isBehindPastTheEnd(ProgramStateRef State, const IteratorPosition &Pos);
bool isZero(ProgramStateRef State, const NonLoc &Val);
bool isZero(ProgramStateRef State, NonLoc Val);
} //namespace
IteratorRangeChecker::IteratorRangeChecker() {
OutOfRangeBugType.reset(
new BugType(this, "Iterator out of range", "Misuse of STL APIs"));
}
void IteratorRangeChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
// Check for out of range access
@ -275,10 +269,10 @@ void IteratorRangeChecker::verifyNext(CheckerContext &C, SVal LHS,
verifyRandomIncrOrDecr(C, OO_Plus, LHS, RHS);
}
void IteratorRangeChecker::reportBug(const StringRef &Message, SVal Val,
void IteratorRangeChecker::reportBug(StringRef Message, SVal Val,
CheckerContext &C,
ExplodedNode *ErrNode) const {
auto R = std::make_unique<PathSensitiveBugReport>(*OutOfRangeBugType, Message,
auto R = std::make_unique<PathSensitiveBugReport>(OutOfRangeBugType, Message,
ErrNode);
const auto *Pos = getIteratorPosition(C.getState(), Val);
@ -295,7 +289,7 @@ bool isLess(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
bool isGreater(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
bool isEqual(ProgramStateRef State, SymbolRef Sym1, SymbolRef Sym2);
bool isZero(ProgramStateRef State, const NonLoc &Val) {
bool isZero(ProgramStateRef State, NonLoc Val) {
auto &BVF = State->getBasicVals();
return compare(State, Val,
nonloc::ConcreteInt(BVF.getValue(llvm::APSInt::get(0))),

View File

@ -62,7 +62,8 @@ class NonLocalizedStringChecker
check::PostObjCMessage,
check::PostStmt<ObjCStringLiteral>> {
mutable std::unique_ptr<BugType> BT;
const BugType BT{this, "Unlocalizable string",
"Localizability Issue (Apple)"};
// Methods that require a localized string
mutable llvm::DenseMap<const IdentifierInfo *,
@ -89,8 +90,6 @@ class NonLocalizedStringChecker
Selector S) const;
public:
NonLocalizedStringChecker();
// When this parameter is set to true, the checker assumes all
// methods that return NSStrings are unlocalized. Thus, more false
// positives will be reported.
@ -108,11 +107,6 @@ class NonLocalizedStringChecker
REGISTER_MAP_WITH_PROGRAMSTATE(LocalizedMemMap, const MemRegion *,
LocalizedState)
NonLocalizedStringChecker::NonLocalizedStringChecker() {
BT.reset(new BugType(this, "Unlocalizable string",
"Localizability Issue (Apple)"));
}
namespace {
class NonLocalizedStringBRVisitor final : public BugReporterVisitor {
@ -764,7 +758,7 @@ void NonLocalizedStringChecker::reportLocalizationError(
// Generate the bug report.
auto R = std::make_unique<PathSensitiveBugReport>(
*BT, "User-facing text should use localized string macro", ErrNode);
BT, "User-facing text should use localized string macro", ErrNode);
if (argumentNumber) {
R->addRange(M.getArgExpr(argumentNumber - 1)->getSourceRange());
} else {

View File

@ -31,7 +31,7 @@ void MPIBugReporter::reportDoubleNonblocking(
RequestRegion->getDescriptiveName() + ". ";
auto Report = std::make_unique<PathSensitiveBugReport>(
*DoubleNonblockingBugType, ErrorText, ExplNode);
DoubleNonblockingBugType, ErrorText, ExplNode);
Report->addRange(MPICallEvent.getSourceRange());
SourceRange Range = RequestRegion->sourceRange();
@ -53,7 +53,7 @@ void MPIBugReporter::reportMissingWait(
std::string ErrorText{"Request " + RequestRegion->getDescriptiveName() +
" has no matching wait. "};
auto Report = std::make_unique<PathSensitiveBugReport>(*MissingWaitBugType,
auto Report = std::make_unique<PathSensitiveBugReport>(MissingWaitBugType,
ErrorText, ExplNode);
SourceRange Range = RequestRegion->sourceRange();
@ -73,7 +73,7 @@ void MPIBugReporter::reportUnmatchedWait(
std::string ErrorText{"Request " + RequestRegion->getDescriptiveName() +
" has no matching nonblocking call. "};
auto Report = std::make_unique<PathSensitiveBugReport>(*UnmatchedWaitBugType,
auto Report = std::make_unique<PathSensitiveBugReport>(UnmatchedWaitBugType,
ErrorText, ExplNode);
Report->addRange(CE.getSourceRange());

View File

@ -17,6 +17,7 @@
#include "MPITypes.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "llvm/ADT/StringRef.h"
namespace clang {
namespace ento {
@ -24,12 +25,10 @@ namespace mpi {
class MPIBugReporter {
public:
MPIBugReporter(const CheckerBase &CB) {
UnmatchedWaitBugType.reset(new BugType(&CB, "Unmatched wait", MPIError));
DoubleNonblockingBugType.reset(
new BugType(&CB, "Double nonblocking", MPIError));
MissingWaitBugType.reset(new BugType(&CB, "Missing wait", MPIError));
}
MPIBugReporter(const CheckerBase &CB)
: UnmatchedWaitBugType(&CB, "Unmatched wait", MPIError),
MissingWaitBugType(&CB, "Missing wait", MPIError),
DoubleNonblockingBugType(&CB, "Double nonblocking", MPIError) {}
/// Report duplicate request use by nonblocking calls without intermediate
/// wait.
@ -68,12 +67,10 @@ class MPIBugReporter {
BugReporter &BReporter) const;
private:
const std::string MPIError = "MPI Error";
// path-sensitive bug types
std::unique_ptr<BugType> UnmatchedWaitBugType;
std::unique_ptr<BugType> MissingWaitBugType;
std::unique_ptr<BugType> DoubleNonblockingBugType;
const llvm::StringLiteral MPIError = "MPI Error";
const BugType UnmatchedWaitBugType;
const BugType MissingWaitBugType;
const BugType DoubleNonblockingBugType;
/// Bug visitor class to find the node where the request region was previously
/// used in order to include it into the BugReport path.

View File

@ -33,7 +33,8 @@ class MacOSKeychainAPIChecker : public Checker<check::PreStmt<CallExpr>,
check::DeadSymbols,
check::PointerEscape,
eval::Assume> {
mutable std::unique_ptr<BugType> BT;
const BugType BT{this, "Improper use of SecKeychain API",
categories::AppleAPIMisuse};
public:
/// AllocationState is a part of the checker specific state together with the
@ -101,12 +102,6 @@ class MacOSKeychainAPIChecker : public Checker<check::PreStmt<CallExpr>,
/// function.
static unsigned getTrackedFunctionIndex(StringRef Name, bool IsAllocator);
inline void initBugType() const {
if (!BT)
BT.reset(new BugType(this, "Improper use of SecKeychain API",
"API Misuse (Apple)"));
}
void generateDeallocatorMismatchReport(const AllocationPair &AP,
const Expr *ArgExpr,
CheckerContext &C) const;
@ -232,7 +227,6 @@ void MacOSKeychainAPIChecker::
if (!N)
return;
initBugType();
SmallString<80> sbuf;
llvm::raw_svector_ostream os(sbuf);
unsigned int PDeallocIdx =
@ -240,7 +234,7 @@ void MacOSKeychainAPIChecker::
os << "Deallocator doesn't match the allocator: '"
<< FunctionsToTrack[PDeallocIdx].Name << "' should be used.";
auto Report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
auto Report = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N);
Report->addVisitor(std::make_unique<SecKeychainBugVisitor>(AP.first));
Report->addRange(ArgExpr->getSourceRange());
markInteresting(Report.get(), AP);
@ -276,7 +270,6 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
ExplodedNode *N = C.generateNonFatalErrorNode(State);
if (!N)
return;
initBugType();
SmallString<128> sbuf;
llvm::raw_svector_ostream os(sbuf);
unsigned int DIdx = FunctionsToTrack[AS->AllocatorIdx].DeallocatorIdx;
@ -284,8 +277,7 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
<< "the allocator: missing a call to '"
<< FunctionsToTrack[DIdx].Name
<< "'.";
auto Report =
std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
auto Report = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N);
Report->addVisitor(std::make_unique<SecKeychainBugVisitor>(V));
Report->addRange(ArgExpr->getSourceRange());
Report->markInteresting(AS->Region);
@ -338,9 +330,8 @@ void MacOSKeychainAPIChecker::checkPreStmt(const CallExpr *CE,
ExplodedNode *N = C.generateNonFatalErrorNode(State);
if (!N)
return;
initBugType();
auto Report = std::make_unique<PathSensitiveBugReport>(
*BT, "Trying to free data which has not been allocated.", N);
BT, "Trying to free data which has not been allocated.", N);
Report->addRange(ArgExpr->getSourceRange());
if (AS)
Report->markInteresting(AS->Region);
@ -474,7 +465,6 @@ std::unique_ptr<PathSensitiveBugReport>
MacOSKeychainAPIChecker::generateAllocatedDataNotReleasedReport(
const AllocationPair &AP, ExplodedNode *N, CheckerContext &C) const {
const ADFunctionInfo &FI = FunctionsToTrack[AP.second->AllocatorIdx];
initBugType();
SmallString<70> sbuf;
llvm::raw_svector_ostream os(sbuf);
os << "Allocated data is not released: missing a call to '"
@ -493,7 +483,7 @@ MacOSKeychainAPIChecker::generateAllocatedDataNotReleasedReport(
AllocNode->getLocationContext());
auto Report = std::make_unique<PathSensitiveBugReport>(
*BT, os.str(), N, LocUsedForUniqueing,
BT, os.str(), N, LocUsedForUniqueing,
AllocNode->getLocationContext()->getDecl());
Report->addVisitor(std::make_unique<SecKeychainBugVisitor>(AP.first));

View File

@ -18,6 +18,7 @@
#include "clang/Basic/TargetInfo.h"
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
@ -31,7 +32,8 @@ using namespace ento;
namespace {
class MacOSXAPIChecker : public Checker< check::PreStmt<CallExpr> > {
mutable std::unique_ptr<BugType> BT_dispatchOnce;
const BugType BT_dispatchOnce{this, "Improper use of 'dispatch_once'",
categories::AppleAPIMisuse};
static const ObjCIvarRegion *getParentIvarRegion(const MemRegion *R);
@ -136,12 +138,8 @@ void MacOSXAPIChecker::CheckDispatchOnce(CheckerContext &C, const CallExpr *CE,
if (!N)
return;
if (!BT_dispatchOnce)
BT_dispatchOnce.reset(new BugType(this, "Improper use of 'dispatch_once'",
"API Misuse (Apple)"));
auto report =
std::make_unique<PathSensitiveBugReport>(*BT_dispatchOnce, os.str(), N);
std::make_unique<PathSensitiveBugReport>(BT_dispatchOnce, os.str(), N);
report->addRange(CE->getArg(0)->getSourceRange());
C.emitReport(std::move(report));
}

View File

@ -30,22 +30,18 @@ namespace {
class MismatchedIteratorChecker
: public Checker<check::PreCall, check::PreStmt<BinaryOperator>> {
std::unique_ptr<BugType> MismatchedBugType;
const BugType MismatchedBugType{this, "Iterator(s) mismatched",
"Misuse of STL APIs",
/*SuppressOnSink=*/true};
void verifyMatch(CheckerContext &C, const SVal &Iter,
const MemRegion *Cont) const;
void verifyMatch(CheckerContext &C, const SVal &Iter1,
const SVal &Iter2) const;
void reportBug(const StringRef &Message, const SVal &Val1,
const SVal &Val2, CheckerContext &C,
ExplodedNode *ErrNode) const;
void reportBug(const StringRef &Message, const SVal &Val,
const MemRegion *Reg, CheckerContext &C,
void verifyMatch(CheckerContext &C, SVal Iter, const MemRegion *Cont) const;
void verifyMatch(CheckerContext &C, SVal Iter1, SVal Iter2) const;
void reportBug(StringRef Message, SVal Val1, SVal Val2, CheckerContext &C,
ExplodedNode *ErrNode) const;
void reportBug(StringRef Message, SVal Val, const MemRegion *Reg,
CheckerContext &C, ExplodedNode *ErrNode) const;
public:
MismatchedIteratorChecker();
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
void checkPreStmt(const BinaryOperator *BO, CheckerContext &C) const;
@ -53,12 +49,6 @@ class MismatchedIteratorChecker
} // namespace
MismatchedIteratorChecker::MismatchedIteratorChecker() {
MismatchedBugType.reset(
new BugType(this, "Iterator(s) mismatched", "Misuse of STL APIs",
/*SuppressOnSink=*/true));
}
void MismatchedIteratorChecker::checkPreCall(const CallEvent &Call,
CheckerContext &C) const {
// Check for iterator mismatches
@ -202,7 +192,7 @@ void MismatchedIteratorChecker::checkPreStmt(const BinaryOperator *BO,
verifyMatch(C, LVal, RVal);
}
void MismatchedIteratorChecker::verifyMatch(CheckerContext &C, const SVal &Iter,
void MismatchedIteratorChecker::verifyMatch(CheckerContext &C, SVal Iter,
const MemRegion *Cont) const {
// Verify match between a container and the container of an iterator
Cont = Cont->getMostDerivedObjectRegion();
@ -238,9 +228,8 @@ void MismatchedIteratorChecker::verifyMatch(CheckerContext &C, const SVal &Iter,
}
}
void MismatchedIteratorChecker::verifyMatch(CheckerContext &C,
const SVal &Iter1,
const SVal &Iter2) const {
void MismatchedIteratorChecker::verifyMatch(CheckerContext &C, SVal Iter1,
SVal Iter2) const {
// Verify match between the containers of two iterators
auto State = C.getState();
const auto *Pos1 = getIteratorPosition(State, Iter1);
@ -277,23 +266,21 @@ void MismatchedIteratorChecker::verifyMatch(CheckerContext &C,
}
}
void MismatchedIteratorChecker::reportBug(const StringRef &Message,
const SVal &Val1,
const SVal &Val2,
CheckerContext &C,
void MismatchedIteratorChecker::reportBug(StringRef Message, SVal Val1,
SVal Val2, CheckerContext &C,
ExplodedNode *ErrNode) const {
auto R = std::make_unique<PathSensitiveBugReport>(*MismatchedBugType, Message,
auto R = std::make_unique<PathSensitiveBugReport>(MismatchedBugType, Message,
ErrNode);
R->markInteresting(Val1);
R->markInteresting(Val2);
C.emitReport(std::move(R));
}
void MismatchedIteratorChecker::reportBug(const StringRef &Message,
const SVal &Val, const MemRegion *Reg,
void MismatchedIteratorChecker::reportBug(StringRef Message, SVal Val,
const MemRegion *Reg,
CheckerContext &C,
ExplodedNode *ErrNode) const {
auto R = std::make_unique<PathSensitiveBugReport>(*MismatchedBugType, Message,
auto R = std::make_unique<PathSensitiveBugReport>(MismatchedBugType, Message,
ErrNode);
R->markInteresting(Val);
R->markInteresting(Reg);

View File

@ -15,6 +15,7 @@
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallDescription.h"
@ -31,7 +32,9 @@ class MmapWriteExecChecker : public Checker<check::PreCall> {
static int ProtWrite;
static int ProtExec;
static int ProtRead;
mutable std::unique_ptr<BugType> BT;
const BugType BT{this, "W^X check fails, Write Exec prot flags set",
"Security"};
public:
MmapWriteExecChecker() : MmapFn({"mmap"}, 6), MprotectFn({"mprotect"}, 3) {}
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
@ -62,17 +65,16 @@ void MmapWriteExecChecker::checkPreCall(const CallEvent &Call,
return;
if ((Prot & (ProtWrite | ProtExec)) == (ProtWrite | ProtExec)) {
if (!BT)
BT.reset(new BugType(this, "W^X check fails, Write Exec prot flags set", "Security"));
ExplodedNode *N = C.generateNonFatalErrorNode();
if (!N)
return;
auto Report = std::make_unique<PathSensitiveBugReport>(
*BT, "Both PROT_WRITE and PROT_EXEC flags are set. This can "
"lead to exploitable memory regions, which could be overwritten "
"with malicious code", N);
BT,
"Both PROT_WRITE and PROT_EXEC flags are set. This can "
"lead to exploitable memory regions, which could be overwritten "
"with malicious code",
N);
Report->addRange(Call.getArgSourceRange(2));
C.emitReport(std::move(Report));
}

View File

@ -31,7 +31,8 @@ using namespace ento;
namespace {
class NSAutoreleasePoolChecker
: public Checker<check::PreObjCMessage> {
mutable std::unique_ptr<BugType> BT;
const BugType BT{this, "Use -drain instead of -release",
"API Upgrade (Apple)"};
mutable Selector releaseS;
public:
@ -57,10 +58,6 @@ void NSAutoreleasePoolChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
if (msg.getSelector() != releaseS)
return;
if (!BT)
BT.reset(new BugType(this, "Use -drain instead of -release",
"API Upgrade (Apple)"));
ExplodedNode *N = C.generateNonFatalErrorNode();
if (!N) {
assert(0);
@ -68,7 +65,7 @@ void NSAutoreleasePoolChecker::checkPreObjCMessage(const ObjCMethodCall &msg,
}
auto Report = std::make_unique<PathSensitiveBugReport>(
*BT,
BT,
"Use -drain instead of -release when using NSAutoreleasePool and "
"garbage collection",
N);

View File

@ -18,6 +18,7 @@
#include "clang/Analysis/AnyCall.h"
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CallEvent.h"
@ -31,8 +32,9 @@ namespace {
class NonNullParamChecker
: public Checker<check::PreCall, check::BeginFunction,
EventDispatcher<ImplicitNullDerefEvent>> {
mutable std::unique_ptr<BugType> BTAttrNonNull;
mutable std::unique_ptr<BugType> BTNullRefArg;
const BugType BTAttrNonNull{
this, "Argument with 'nonnull' attribute passed null", "API"};
const BugType BTNullRefArg{this, "Dereference of null pointer"};
public:
void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
@ -278,13 +280,6 @@ std::unique_ptr<PathSensitiveBugReport>
NonNullParamChecker::genReportNullAttrNonNull(const ExplodedNode *ErrorNode,
const Expr *ArgE,
unsigned IdxOfArg) const {
// Lazily allocate the BugType object if it hasn't already been
// created. Ownership is transferred to the BugReporter object once
// the BugReport is passed to 'EmitWarning'.
if (!BTAttrNonNull)
BTAttrNonNull.reset(new BugType(
this, "Argument with 'nonnull' attribute passed null", "API"));
llvm::SmallString<256> SBuf;
llvm::raw_svector_ostream OS(SBuf);
OS << "Null pointer passed to "
@ -292,7 +287,7 @@ NonNullParamChecker::genReportNullAttrNonNull(const ExplodedNode *ErrorNode,
<< " parameter expecting 'nonnull'";
auto R =
std::make_unique<PathSensitiveBugReport>(*BTAttrNonNull, SBuf, ErrorNode);
std::make_unique<PathSensitiveBugReport>(BTAttrNonNull, SBuf, ErrorNode);
if (ArgE)
bugreporter::trackExpressionValue(ErrorNode, ArgE, *R);
@ -302,11 +297,8 @@ NonNullParamChecker::genReportNullAttrNonNull(const ExplodedNode *ErrorNode,
std::unique_ptr<PathSensitiveBugReport>
NonNullParamChecker::genReportReferenceToNullPointer(
const ExplodedNode *ErrorNode, const Expr *ArgE) const {
if (!BTNullRefArg)
BTNullRefArg.reset(new BugType(this, "Dereference of null pointer"));
auto R = std::make_unique<PathSensitiveBugReport>(
*BTNullRefArg, "Forming reference to null pointer", ErrorNode);
BTNullRefArg, "Forming reference to null pointer", ErrorNode);
if (ArgE) {
const Expr *ArgEDeref = bugreporter::getDerefExpr(ArgE);
if (!ArgEDeref)
@ -314,7 +306,6 @@ NonNullParamChecker::genReportReferenceToNullPointer(
bugreporter::trackExpressionValue(ErrorNode, ArgEDeref, *R);
}
return R;
}
void ento::registerNonNullParamChecker(CheckerManager &mgr) {

View File

@ -25,8 +25,10 @@ using namespace ento;
namespace {
class ObjCAtSyncChecker
: public Checker< check::PreStmt<ObjCAtSynchronizedStmt> > {
mutable std::unique_ptr<BugType> BT_null;
mutable std::unique_ptr<BugType> BT_undef;
const BugType BT_null{this, "Nil value used as mutex for @synchronized() "
"(no synchronization will occur)"};
const BugType BT_undef{this, "Uninitialized value used as mutex "
"for @synchronized"};
public:
void checkPreStmt(const ObjCAtSynchronizedStmt *S, CheckerContext &C) const;
@ -43,11 +45,8 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
// Uninitialized value used for the mutex?
if (isa<UndefinedVal>(V)) {
if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT_undef)
BT_undef.reset(new BugType(this, "Uninitialized value used as mutex "
"for @synchronized"));
auto report = std::make_unique<PathSensitiveBugReport>(
*BT_undef, BT_undef->getDescription(), N);
BT_undef, BT_undef.getDescription(), N);
bugreporter::trackExpressionValue(N, Ex, *report);
C.emitReport(std::move(report));
}
@ -66,12 +65,8 @@ void ObjCAtSyncChecker::checkPreStmt(const ObjCAtSynchronizedStmt *S,
// Generate an error node. This isn't a sink since
// a null mutex just means no synchronization occurs.
if (ExplodedNode *N = C.generateNonFatalErrorNode(nullState)) {
if (!BT_null)
BT_null.reset(
new BugType(this, "Nil value used as mutex for @synchronized() "
"(no synchronization will occur)"));
auto report = std::make_unique<PathSensitiveBugReport>(
*BT_null, BT_null->getDescription(), N);
BT_null, BT_null.getDescription(), N);
bugreporter::trackExpressionValue(N, Ex, *report);
C.emitReport(std::move(report));

View File

@ -30,12 +30,7 @@ namespace {
class ObjCContainersChecker : public Checker< check::PreStmt<CallExpr>,
check::PostStmt<CallExpr>,
check::PointerEscape> {
mutable std::unique_ptr<BugType> BT;
inline void initBugType() const {
if (!BT)
BT.reset(new BugType(this, "CFArray API",
categories::CoreFoundationObjectiveC));
}
const BugType BT{this, "CFArray API", categories::CoreFoundationObjectiveC};
inline SymbolRef getArraySym(const Expr *E, CheckerContext &C) const {
SVal ArrayRef = C.getSVal(E);
@ -140,9 +135,9 @@ void ObjCContainersChecker::checkPreStmt(const CallExpr *CE,
ExplodedNode *N = C.generateErrorNode(StOutBound);
if (!N)
return;
initBugType();
auto R = std::make_unique<PathSensitiveBugReport>(
*BT, "Index is out of bounds", N);
BT, "Index is out of bounds", N);
R->addRange(IdxExpr->getSourceRange());
bugreporter::trackExpressionValue(N, IdxExpr, *R,
{bugreporter::TrackingKind::Thorough,

View File

@ -61,13 +61,13 @@ class ObjCSelfInitChecker : public Checker< check::PostObjCMessage,
check::PostCall,
check::Location,
check::Bind > {
mutable std::unique_ptr<BugType> BT;
const BugType BT{this, "Missing \"self = [(super or self) init...]\"",
categories::CoreFoundationObjectiveC};
void checkForInvalidSelf(const Expr *E, CheckerContext &C,
const char *errorStr) const;
public:
ObjCSelfInitChecker() {}
void checkPostObjCMessage(const ObjCMethodCall &Msg, CheckerContext &C) const;
void checkPostStmt(const ObjCIvarRefExpr *E, CheckerContext &C) const;
void checkPreStmt(const ReturnStmt *S, CheckerContext &C) const;
@ -157,10 +157,7 @@ void ObjCSelfInitChecker::checkForInvalidSelf(const Expr *E, CheckerContext &C,
if (!N)
return;
if (!BT)
BT.reset(new BugType(this, "Missing \"self = [(super or self) init...]\"",
categories::CoreFoundationObjectiveC));
C.emitReport(std::make_unique<PathSensitiveBugReport>(*BT, errorStr, N));
C.emitReport(std::make_unique<PathSensitiveBugReport>(BT, errorStr, N));
}
void ObjCSelfInitChecker::checkPostObjCMessage(const ObjCMethodCall &Msg,

View File

@ -26,18 +26,19 @@ namespace {
class ObjCSuperDeallocChecker
: public Checker<check::PostObjCMessage, check::PreObjCMessage,
check::PreCall, check::Location> {
mutable IdentifierInfo *IIdealloc, *IINSObject;
mutable IdentifierInfo *IIdealloc = nullptr;
mutable IdentifierInfo *IINSObject = nullptr;
mutable Selector SELdealloc;
std::unique_ptr<BugType> DoubleSuperDeallocBugType;
const BugType DoubleSuperDeallocBugType{
this, "[super dealloc] should not be called more than once",
categories::CoreFoundationObjectiveC};
void initIdentifierInfoAndSelectors(ASTContext &Ctx) const;
bool isSuperDeallocMessage(const ObjCMethodCall &M) const;
public:
ObjCSuperDeallocChecker();
void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const;
@ -188,7 +189,7 @@ void ObjCSuperDeallocChecker::reportUseAfterDealloc(SymbolRef Sym,
Desc = "Use of 'self' after it has been deallocated";
// Generate the report.
auto BR = std::make_unique<PathSensitiveBugReport>(*DoubleSuperDeallocBugType,
auto BR = std::make_unique<PathSensitiveBugReport>(DoubleSuperDeallocBugType,
Desc, ErrNode);
BR->addRange(S->getSourceRange());
BR->addVisitor(std::make_unique<SuperDeallocBRVisitor>(Sym));
@ -213,14 +214,6 @@ void ObjCSuperDeallocChecker::diagnoseCallArguments(const CallEvent &CE,
}
}
ObjCSuperDeallocChecker::ObjCSuperDeallocChecker()
: IIdealloc(nullptr), IINSObject(nullptr) {
DoubleSuperDeallocBugType.reset(
new BugType(this, "[super dealloc] should not be called more than once",
categories::CoreFoundationObjectiveC));
}
void
ObjCSuperDeallocChecker::initIdentifierInfoAndSelectors(ASTContext &Ctx) const {
if (IIdealloc)

View File

@ -32,7 +32,7 @@ using namespace ento;
namespace {
class PaddingChecker : public Checker<check::ASTDecl<TranslationUnitDecl>> {
private:
mutable std::unique_ptr<BugType> PaddingBug;
const BugType PaddingBug{this, "Excessive Padding", "Performance"};
mutable BugReporter *BR;
public:
@ -310,10 +310,6 @@ class PaddingChecker : public Checker<check::ASTDecl<TranslationUnitDecl>> {
void reportRecord(
const RecordDecl *RD, CharUnits BaselinePad, CharUnits OptimalPad,
const SmallVector<const FieldDecl *, 20> &OptimalFieldsOrder) const {
if (!PaddingBug)
PaddingBug =
std::make_unique<BugType>(this, "Excessive Padding", "Performance");
SmallString<100> Buf;
llvm::raw_svector_ostream Os(Buf);
Os << "Excessive padding in '";
@ -341,8 +337,7 @@ class PaddingChecker : public Checker<check::ASTDecl<TranslationUnitDecl>> {
PathDiagnosticLocation CELoc =
PathDiagnosticLocation::create(RD, BR->getSourceManager());
auto Report =
std::make_unique<BasicBugReport>(*PaddingBug, Os.str(), CELoc);
auto Report = std::make_unique<BasicBugReport>(PaddingBug, Os.str(), CELoc);
Report->setDeclWithIssue(RD);
Report->addRange(RD->getSourceRange());
BR->emitReport(std::move(Report));

View File

@ -56,8 +56,8 @@ class PointerArithChecker
bool PointedNeeded = false) const;
void initAllocIdentifiers(ASTContext &C) const;
mutable std::unique_ptr<BugType> BT_pointerArith;
mutable std::unique_ptr<BugType> BT_polyArray;
const BugType BT_pointerArith{this, "Dangerous pointer arithmetic"};
const BugType BT_polyArray{this, "Dangerous pointer arithmetic"};
mutable llvm::SmallSet<IdentifierInfo *, 8> AllocFunctions;
public:
@ -168,12 +168,10 @@ void PointerArithChecker::reportPointerArithMisuse(const Expr *E,
if (!IsPolymorphic)
return;
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
if (!BT_polyArray)
BT_polyArray.reset(new BugType(this, "Dangerous pointer arithmetic"));
constexpr llvm::StringLiteral Msg =
"Pointer arithmetic on a pointer to base class is dangerous "
"because derived and base class may have different size.";
auto R = std::make_unique<PathSensitiveBugReport>(*BT_polyArray, Msg, N);
auto R = std::make_unique<PathSensitiveBugReport>(BT_polyArray, Msg, N);
R->addRange(E->getSourceRange());
R->markInteresting(ArrayRegion);
C.emitReport(std::move(R));
@ -190,12 +188,10 @@ void PointerArithChecker::reportPointerArithMisuse(const Expr *E,
return;
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
if (!BT_pointerArith)
BT_pointerArith.reset(new BugType(this, "Dangerous pointer arithmetic"));
constexpr llvm::StringLiteral Msg =
"Pointer arithmetic on non-array variables relies on memory layout, "
"which is dangerous.";
auto R = std::make_unique<PathSensitiveBugReport>(*BT_pointerArith, Msg, N);
auto R = std::make_unique<PathSensitiveBugReport>(BT_pointerArith, Msg, N);
R->addRange(SR);
R->markInteresting(Region);
C.emitReport(std::move(R));

View File

@ -25,7 +25,7 @@ using namespace ento;
namespace {
class PointerSubChecker
: public Checker< check::PreStmt<BinaryOperator> > {
mutable std::unique_ptr<BugType> BT;
const BugType BT{this, "Pointer subtraction"};
public:
void checkPreStmt(const BinaryOperator *B, CheckerContext &C) const;
@ -59,12 +59,10 @@ void PointerSubChecker::checkPreStmt(const BinaryOperator *B,
return;
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
if (!BT)
BT.reset(new BugType(this, "Pointer subtraction"));
constexpr llvm::StringLiteral Msg =
"Subtraction of two pointers that do not point to the same memory "
"chunk may cause incorrect result.";
auto R = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
auto R = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
R->addRange(B->getSourceRange());
C.emitReport(std::move(R));
}

View File

@ -26,7 +26,9 @@ using namespace ento;
namespace {
class ReturnPointerRangeChecker :
public Checker< check::PreStmt<ReturnStmt> > {
mutable std::unique_ptr<BugType> BT;
// FIXME: This bug correspond to CWE-466. Eventually we should have bug
// types explicitly reference such exploit categories (when applicable).
const BugType BT{this, "Buffer overflow"};
public:
void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
@ -76,16 +78,12 @@ void ReturnPointerRangeChecker::checkPreStmt(const ReturnStmt *RS,
if (!N)
return;
// FIXME: This bug correspond to CWE-466. Eventually we should have bug
// types explicitly reference such exploit categories (when applicable).
if (!BT)
BT.reset(new BugType(this, "Buffer overflow"));
constexpr llvm::StringLiteral Msg =
"Returned pointer value points outside the original object "
"(potential buffer overflow)";
// Generate a report for this bug.
auto Report = std::make_unique<PathSensitiveBugReport>(*BT, Msg, N);
auto Report = std::make_unique<PathSensitiveBugReport>(BT, Msg, N);
Report->addRange(RetE->getSourceRange());
const auto ConcreteElementCount = ElementCount.getAs<nonloc::ConcreteInt>();

View File

@ -24,8 +24,8 @@ using namespace ento;
namespace {
class ReturnUndefChecker : public Checker< check::PreStmt<ReturnStmt> > {
mutable std::unique_ptr<BugType> BT_Undef;
mutable std::unique_ptr<BugType> BT_NullReference;
const BugType BT_Undef{this, "Garbage return value"};
const BugType BT_NullReference{this, "Returning null reference"};
void emitUndef(CheckerContext &C, const Expr *RetE) const;
void checkReference(CheckerContext &C, const Expr *RetE,
@ -77,7 +77,7 @@ void ReturnUndefChecker::checkPreStmt(const ReturnStmt *RS,
}
}
static void emitBug(CheckerContext &C, BugType &BT, StringRef Msg,
static void emitBug(CheckerContext &C, const BugType &BT, StringRef Msg,
const Expr *RetE, const Expr *TrackingE = nullptr) {
ExplodedNode *N = C.generateErrorNode();
if (!N)
@ -92,9 +92,7 @@ static void emitBug(CheckerContext &C, BugType &BT, StringRef Msg,
}
void ReturnUndefChecker::emitUndef(CheckerContext &C, const Expr *RetE) const {
if (!BT_Undef)
BT_Undef.reset(new BugType(this, "Garbage return value"));
emitBug(C, *BT_Undef, "Undefined or garbage value returned to caller", RetE);
emitBug(C, BT_Undef, "Undefined or garbage value returned to caller", RetE);
}
void ReturnUndefChecker::checkReference(CheckerContext &C, const Expr *RetE,
@ -109,10 +107,7 @@ void ReturnUndefChecker::checkReference(CheckerContext &C, const Expr *RetE,
}
// The return value is known to be null. Emit a bug report.
if (!BT_NullReference)
BT_NullReference.reset(new BugType(this, "Returning null reference"));
emitBug(C, *BT_NullReference, BT_NullReference->getDescription(), RetE,
emitBug(C, BT_NullReference, BT_NullReference.getDescription(), RetE,
bugreporter::getDerefExpr(RetE));
}

View File

@ -52,10 +52,13 @@ class SimpleStreamChecker : public Checker<check::PostCall,
check::PreCall,
check::DeadSymbols,
check::PointerEscape> {
CallDescription OpenFn, CloseFn;
const CallDescription OpenFn{{"fopen"}, 2};
const CallDescription CloseFn{{"fclose"}, 1};
std::unique_ptr<BugType> DoubleCloseBugType;
std::unique_ptr<BugType> LeakBugType;
const BugType DoubleCloseBugType{this, "Double fclose",
"Unix Stream API Error"};
const BugType LeakBugType{this, "Resource Leak", "Unix Stream API Error",
/*SuppressOnSink=*/true};
void reportDoubleClose(SymbolRef FileDescSym,
const CallEvent &Call,
@ -67,8 +70,6 @@ class SimpleStreamChecker : public Checker<check::PostCall,
bool guaranteedNotToCloseFile(const CallEvent &Call) const;
public:
SimpleStreamChecker();
/// Process fopen.
void checkPostCall(const CallEvent &Call, CheckerContext &C) const;
/// Process fclose.
@ -89,18 +90,6 @@ class SimpleStreamChecker : public Checker<check::PostCall,
/// state. Let's store it in the ProgramState.
REGISTER_MAP_WITH_PROGRAMSTATE(StreamMap, SymbolRef, StreamState)
SimpleStreamChecker::SimpleStreamChecker()
: OpenFn({"fopen"}, 2), CloseFn({"fclose"}, 1) {
// Initialize the bug types.
DoubleCloseBugType.reset(
new BugType(this, "Double fclose", "Unix Stream API Error"));
// Sinks are higher importance bugs as well as calls to assert() or exit(0).
LeakBugType.reset(
new BugType(this, "Resource Leak", "Unix Stream API Error",
/*SuppressOnSink=*/true));
}
void SimpleStreamChecker::checkPostCall(const CallEvent &Call,
CheckerContext &C) const {
if (!Call.isGlobalCFunction())
@ -192,7 +181,7 @@ void SimpleStreamChecker::reportDoubleClose(SymbolRef FileDescSym,
// Generate the report.
auto R = std::make_unique<PathSensitiveBugReport>(
*DoubleCloseBugType, "Closing a previously closed file stream", ErrNode);
DoubleCloseBugType, "Closing a previously closed file stream", ErrNode);
R->addRange(Call.getSourceRange());
R->markInteresting(FileDescSym);
C.emitReport(std::move(R));
@ -205,7 +194,7 @@ void SimpleStreamChecker::reportLeaks(ArrayRef<SymbolRef> LeakedStreams,
// TODO: Identify the leaked file descriptor.
for (SymbolRef LeakedStream : LeakedStreams) {
auto R = std::make_unique<PathSensitiveBugReport>(
*LeakBugType, "Opened file is never closed; potential resource leak",
LeakBugType, "Opened file is never closed; potential resource leak",
ErrNode);
R->markInteresting(LeakedStream);
C.emitReport(std::move(R));

View File

@ -823,7 +823,7 @@ class StdLibraryFunctionsChecker
using FunctionSummaryMapType = llvm::DenseMap<const FunctionDecl *, Summary>;
mutable FunctionSummaryMapType FunctionSummaryMap;
mutable std::unique_ptr<BugType> BT_InvalidArg;
const BugType BT_InvalidArg{this, "Function call with invalid argument"};
mutable bool SummariesInitialized = false;
static SVal getArgSVal(const CallEvent &Call, ArgNo ArgN) {
@ -875,11 +875,7 @@ class StdLibraryFunctionsChecker
VC->describe(ValueConstraint::Violation, Call, C.getState(), Summary,
MsgOs);
Msg[0] = toupper(Msg[0]);
if (!BT_InvalidArg)
BT_InvalidArg = std::make_unique<BugType>(
CheckName, "Function call with invalid argument",
categories::LogicError);
auto R = std::make_unique<PathSensitiveBugReport>(*BT_InvalidArg, Msg, N);
auto R = std::make_unique<PathSensitiveBugReport>(BT_InvalidArg, Msg, N);
for (ArgNo ArgN : VC->getArgsToTrack()) {
bugreporter::trackExpressionValue(N, Call.getArgExpr(ArgN), *R);
@ -2244,6 +2240,14 @@ void StdLibraryFunctionsChecker::initFunctionSummaries(
.ArgConstraint(NotNull(ArgNo(0)))
.ArgConstraint(NotNull(ArgNo(1))));
// int fflush(FILE *stream);
addToFunctionSummaryMap(
"fflush", Signature(ArgTypes{FilePtrTy}, RetType{IntTy}),
Summary(NoEvalCall)
.Case(ReturnsZero, ErrnoMustNotBeChecked, GenericSuccessMsg)
.Case({ReturnValueCondition(WithinRange, SingleValue(EOFv))},
ErrnoNEZeroIrrelevant, GenericFailureMsg));
// long ftell(FILE *stream);
// From 'The Open Group Base Specifications Issue 7, 2018 edition':
// "The ftell() function shall not change the setting of errno if

View File

@ -52,7 +52,7 @@ removeInformationStoredForDeadInstances(const CallEvent &Call,
template <class TypeMap>
void handleConstructorAndAssignment(const CallEvent &Call, CheckerContext &C,
const SVal &ThisSVal) {
SVal ThisSVal) {
ProgramStateRef State = Call.getState();
if (!State)

View File

@ -23,8 +23,7 @@ using namespace taint;
namespace {
class TaintTesterChecker : public Checker<check::PostStmt<Expr>> {
std::unique_ptr<BugType> BT =
std::make_unique<BugType>(this, "Tainted data", "General");
const BugType BT{this, "Tainted data", "General"};
public:
void checkPostStmt(const Expr *E, CheckerContext &C) const;
@ -39,7 +38,7 @@ void TaintTesterChecker::checkPostStmt(const Expr *E,
if (isTainted(State, E, C.getLocationContext())) {
if (ExplodedNode *N = C.generateNonFatalErrorNode()) {
auto report = std::make_unique<PathSensitiveBugReport>(*BT, "tainted", N);
auto report = std::make_unique<PathSensitiveBugReport>(BT, "tainted", N);
report->addRange(E->getSourceRange());
C.emitReport(std::move(report));
}

View File

@ -78,7 +78,7 @@ class DivisionBRVisitor : public BugReporterVisitor {
class TestAfterDivZeroChecker
: public Checker<check::PreStmt<BinaryOperator>, check::BranchCondition,
check::EndFunction> {
mutable std::unique_ptr<BugType> DivZeroBug;
const BugType DivZeroBug{this, "Division by zero"};
void reportBug(SVal Val, CheckerContext &C) const;
public:
@ -165,12 +165,10 @@ bool TestAfterDivZeroChecker::hasDivZeroMap(SVal Var,
void TestAfterDivZeroChecker::reportBug(SVal Val, CheckerContext &C) const {
if (ExplodedNode *N = C.generateErrorNode(C.getState())) {
if (!DivZeroBug)
DivZeroBug.reset(new BugType(this, "Division by zero"));
auto R = std::make_unique<PathSensitiveBugReport>(
*DivZeroBug, "Value being compared against zero has already been used "
"for division",
DivZeroBug,
"Value being compared against zero has already been used "
"for division",
N);
R->addVisitor(std::make_unique<DivisionBRVisitor>(Val.getAsSymbol(),

View File

@ -27,7 +27,7 @@ using namespace ento;
namespace {
class UndefBranchChecker : public Checker<check::BranchCondition> {
mutable std::unique_ptr<BugType> BT;
const BugType BT{this, "Branch condition evaluates to a garbage value"};
struct FindUndefExpr {
ProgramStateRef St;
@ -64,52 +64,47 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
// ObjCForCollection is a loop, but has no actual condition.
if (isa<ObjCForCollectionStmt>(Condition))
return;
SVal X = Ctx.getSVal(Condition);
if (X.isUndef()) {
// Generate a sink node, which implicitly marks both outgoing branches as
// infeasible.
ExplodedNode *N = Ctx.generateErrorNode();
if (N) {
if (!BT)
BT.reset(
new BugType(this, "Branch condition evaluates to a garbage value"));
if (!Ctx.getSVal(Condition).isUndef())
return;
// What's going on here: we want to highlight the subexpression of the
// condition that is the most likely source of the "uninitialized
// branch condition." We do a recursive walk of the condition's
// subexpressions and roughly look for the most nested subexpression
// that binds to Undefined. We then highlight that expression's range.
// Generate a sink node, which implicitly marks both outgoing branches as
// infeasible.
ExplodedNode *N = Ctx.generateErrorNode();
if (!N)
return;
// What's going on here: we want to highlight the subexpression of the
// condition that is the most likely source of the "uninitialized
// branch condition." We do a recursive walk of the condition's
// subexpressions and roughly look for the most nested subexpression
// that binds to Undefined. We then highlight that expression's range.
// Get the predecessor node and check if is a PostStmt with the Stmt
// being the terminator condition. We want to inspect the state
// of that node instead because it will contain main information about
// the subexpressions.
// Get the predecessor node and check if is a PostStmt with the Stmt
// being the terminator condition. We want to inspect the state
// of that node instead because it will contain main information about
// the subexpressions.
// Note: any predecessor will do. They should have identical state,
// since all the BlockEdge did was act as an error sink since the value
// had to already be undefined.
assert (!N->pred_empty());
const Expr *Ex = cast<Expr>(Condition);
ExplodedNode *PrevN = *N->pred_begin();
ProgramPoint P = PrevN->getLocation();
ProgramStateRef St = N->getState();
// Note: any predecessor will do. They should have identical state,
// since all the BlockEdge did was act as an error sink since the value
// had to already be undefined.
assert(!N->pred_empty());
const Expr *Ex = cast<Expr>(Condition);
ExplodedNode *PrevN = *N->pred_begin();
ProgramPoint P = PrevN->getLocation();
ProgramStateRef St = N->getState();
if (std::optional<PostStmt> PS = P.getAs<PostStmt>())
if (PS->getStmt() == Ex)
St = PrevN->getState();
if (std::optional<PostStmt> PS = P.getAs<PostStmt>())
if (PS->getStmt() == Ex)
St = PrevN->getState();
FindUndefExpr FindIt(St, Ctx.getLocationContext());
Ex = FindIt.FindExpr(Ex);
FindUndefExpr FindIt(St, Ctx.getLocationContext());
Ex = FindIt.FindExpr(Ex);
// Emit the bug report.
auto R = std::make_unique<PathSensitiveBugReport>(
*BT, BT->getDescription(), N);
bugreporter::trackExpressionValue(N, Ex, *R);
R->addRange(Ex->getSourceRange());
// Emit the bug report.
auto R = std::make_unique<PathSensitiveBugReport>(BT, BT.getDescription(), N);
bugreporter::trackExpressionValue(N, Ex, *R);
R->addRange(Ex->getSourceRange());
Ctx.emitReport(std::move(R));
}
}
Ctx.emitReport(std::move(R));
}
void ento::registerUndefBranchChecker(CheckerManager &mgr) {

View File

@ -27,7 +27,7 @@ using namespace ento;
namespace {
class UndefCapturedBlockVarChecker
: public Checker< check::PostStmt<BlockExpr> > {
mutable std::unique_ptr<BugType> BT;
const BugType BT{this, "uninitialized variable captured by block"};
public:
void checkPostStmt(const BlockExpr *BE, CheckerContext &C) const;
@ -70,10 +70,6 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
if (std::optional<UndefinedVal> V =
state->getSVal(Var.getOriginalRegion()).getAs<UndefinedVal>()) {
if (ExplodedNode *N = C.generateErrorNode()) {
if (!BT)
BT.reset(
new BugType(this, "uninitialized variable captured by block"));
// Generate a bug report.
SmallString<128> buf;
llvm::raw_svector_ostream os(buf);
@ -81,7 +77,7 @@ UndefCapturedBlockVarChecker::checkPostStmt(const BlockExpr *BE,
os << "Variable '" << VD->getName()
<< "' is uninitialized when captured by block";
auto R = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
auto R = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N);
if (const Expr *Ex = FindBlockDeclRefExpr(BE->getBody(), VD))
R->addRange(Ex->getSourceRange());
bugreporter::trackStoredValue(*V, VR, *R,

View File

@ -28,7 +28,7 @@ namespace {
class UndefResultChecker
: public Checker< check::PostStmt<BinaryOperator> > {
mutable std::unique_ptr<BugType> BT;
const BugType BT{this, "Result of operation is garbage or undefined"};
public:
void checkPostStmt(const BinaryOperator *B, CheckerContext &C) const;
@ -74,10 +74,6 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
if (!N)
return;
if (!BT)
BT.reset(
new BugType(this, "Result of operation is garbage or undefined"));
SmallString<256> sbuf;
llvm::raw_svector_ostream OS(sbuf);
const Expr *Ex = nullptr;
@ -104,7 +100,7 @@ void UndefResultChecker::checkPostStmt(const BinaryOperator *B,
<< BinaryOperator::getOpcodeStr(B->getOpcode())
<< "' expression is undefined";
}
auto report = std::make_unique<PathSensitiveBugReport>(*BT, OS.str(), N);
auto report = std::make_unique<PathSensitiveBugReport>(BT, OS.str(), N);
if (Ex) {
report->addRange(Ex->getSourceRange());
bugreporter::trackExpressionValue(N, Ex, *report);

View File

@ -24,7 +24,7 @@ using namespace ento;
namespace {
class UndefinedArraySubscriptChecker
: public Checker< check::PreStmt<ArraySubscriptExpr> > {
mutable std::unique_ptr<BugType> BT;
const BugType BT{this, "Array subscript is undefined"};
public:
void checkPreStmt(const ArraySubscriptExpr *A, CheckerContext &C) const;
@ -48,11 +48,8 @@ UndefinedArraySubscriptChecker::checkPreStmt(const ArraySubscriptExpr *A,
ExplodedNode *N = C.generateErrorNode();
if (!N)
return;
if (!BT)
BT.reset(new BugType(this, "Array subscript is undefined"));
// Generate a report for this bug.
auto R = std::make_unique<PathSensitiveBugReport>(*BT, BT->getDescription(), N);
auto R = std::make_unique<PathSensitiveBugReport>(BT, BT.getDescription(), N);
R->addRange(A->getIdx()->getSourceRange());
bugreporter::trackExpressionValue(N, A->getIdx(), *R);
C.emitReport(std::move(R));

View File

@ -23,7 +23,7 @@ using namespace ento;
namespace {
class UndefinedAssignmentChecker
: public Checker<check::Bind> {
mutable std::unique_ptr<BugType> BT;
const BugType BT{this, "Assigned value is garbage or undefined"};
public:
void checkBind(SVal location, SVal val, const Stmt *S,
@ -49,11 +49,6 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
if (!N)
return;
static const char *const DefaultMsg =
"Assigned value is garbage or undefined";
if (!BT)
BT.reset(new BugType(this, DefaultMsg));
// Generate a report for this bug.
llvm::SmallString<128> Str;
llvm::raw_svector_ostream OS(Str);
@ -105,9 +100,9 @@ void UndefinedAssignmentChecker::checkBind(SVal location, SVal val,
}
if (OS.str().empty())
OS << DefaultMsg;
OS << BT.getDescription();
auto R = std::make_unique<PathSensitiveBugReport>(*BT, OS.str(), N);
auto R = std::make_unique<PathSensitiveBugReport>(BT, OS.str(), N);
if (ex) {
R->addRange(ex->getSourceRange());
bugreporter::trackExpressionValue(N, ex, *R);

View File

@ -299,7 +299,7 @@ class FindUninitializedFields {
bool isDereferencableUninit(const FieldRegion *FR, FieldChainInfo LocalChain);
/// Returns true if the value of a primitive object is uninitialized.
bool isPrimitiveUninit(const SVal &V);
bool isPrimitiveUninit(SVal V);
// Note that we don't have a method for arrays -- the elements of an array are
// often left uninitialized intentionally even when it is of a C++ record

View File

@ -38,15 +38,12 @@ namespace {
class UninitializedObjectChecker
: public Checker<check::EndFunction, check::DeadSymbols> {
std::unique_ptr<BugType> BT_uninitField;
const BugType BT_uninitField{this, "Uninitialized fields"};
public:
// The fields of this struct will be initialized when registering the checker.
UninitObjCheckerOptions Opts;
UninitializedObjectChecker()
: BT_uninitField(new BugType(this, "Uninitialized fields")) {}
void checkEndFunction(const ReturnStmt *RS, CheckerContext &C) const;
void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const;
};
@ -186,7 +183,7 @@ void UninitializedObjectChecker::checkEndFunction(
for (const auto &Pair : UninitFields) {
auto Report = std::make_unique<PathSensitiveBugReport>(
*BT_uninitField, Pair.second, Node, LocUsedForUniqueing,
BT_uninitField, Pair.second, Node, LocUsedForUniqueing,
Node->getLocationContext()->getDecl());
Context.emitReport(std::move(Report));
}
@ -200,7 +197,7 @@ void UninitializedObjectChecker::checkEndFunction(
<< " at the end of the constructor call";
auto Report = std::make_unique<PathSensitiveBugReport>(
*BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing,
BT_uninitField, WarningOS.str(), Node, LocUsedForUniqueing,
Node->getLocationContext()->getDecl());
for (const auto &Pair : UninitFields) {
@ -379,7 +376,7 @@ bool FindUninitializedFields::isUnionUninit(const TypedValueRegion *R) {
return false;
}
bool FindUninitializedFields::isPrimitiveUninit(const SVal &V) {
bool FindUninitializedFields::isPrimitiveUninit(SVal V) {
if (V.isUndef())
return true;

View File

@ -11,9 +11,10 @@
//
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/Basic/TargetInfo.h"
#include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/CommonBugCategories.h"
#include "clang/StaticAnalyzer/Core/Checker.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
@ -39,7 +40,9 @@ enum class OpenVariant {
namespace {
class UnixAPIMisuseChecker : public Checker< check::PreStmt<CallExpr> > {
mutable std::unique_ptr<BugType> BT_open, BT_pthreadOnce;
const BugType BT_open{this, "Improper use of 'open'", categories::UnixAPI};
const BugType BT_pthreadOnce{this, "Improper use of 'pthread_once'",
categories::UnixAPI};
mutable std::optional<uint64_t> Val_O_CREAT;
public:
@ -64,7 +67,9 @@ class UnixAPIPortabilityChecker : public Checker< check::PreStmt<CallExpr> > {
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
private:
mutable std::unique_ptr<BugType> BT_mallocZero;
const BugType BT_mallocZero{
this, "Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)",
categories::UnixAPI};
void CheckCallocZero(CheckerContext &C, const CallExpr *CE) const;
void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const;
@ -87,14 +92,6 @@ class UnixAPIPortabilityChecker : public Checker< check::PreStmt<CallExpr> > {
} //end anonymous namespace
static void LazyInitialize(const CheckerBase *Checker,
std::unique_ptr<BugType> &BT,
const char *name) {
if (BT)
return;
BT.reset(new BugType(Checker, name, categories::UnixAPI));
}
//===----------------------------------------------------------------------===//
// "open" (man 2 open)
//===----------------------------------------------------------------------===/
@ -132,9 +129,7 @@ void UnixAPIMisuseChecker::ReportOpenBug(CheckerContext &C,
if (!N)
return;
LazyInitialize(this, BT_open, "Improper use of 'open'");
auto Report = std::make_unique<PathSensitiveBugReport>(*BT_open, Msg, N);
auto Report = std::make_unique<PathSensitiveBugReport>(BT_open, Msg, N);
Report->addRange(SR);
C.emitReport(std::move(Report));
}
@ -301,10 +296,8 @@ void UnixAPIMisuseChecker::CheckPthreadOnce(CheckerContext &C,
if (isa<VarRegion>(R) && isa<StackLocalsSpaceRegion>(R->getMemorySpace()))
os << " Perhaps you intended to declare the variable as 'static'?";
LazyInitialize(this, BT_pthreadOnce, "Improper use of 'pthread_once'");
auto report =
std::make_unique<PathSensitiveBugReport>(*BT_pthreadOnce, os.str(), N);
std::make_unique<PathSensitiveBugReport>(BT_pthreadOnce, os.str(), N);
report->addRange(CE->getArg(0)->getSourceRange());
C.emitReport(std::move(report));
}
@ -341,14 +334,11 @@ bool UnixAPIPortabilityChecker::ReportZeroByteAllocation(
if (!N)
return false;
LazyInitialize(this, BT_mallocZero,
"Undefined allocation of 0 bytes (CERT MEM04-C; CWE-131)");
SmallString<256> S;
llvm::raw_svector_ostream os(S);
os << "Call to '" << fn_name << "' has an allocation size of 0 bytes";
auto report =
std::make_unique<PathSensitiveBugReport>(*BT_mallocZero, os.str(), N);
std::make_unique<PathSensitiveBugReport>(BT_mallocZero, os.str(), N);
report->addRange(arg->getSourceRange());
bugreporter::trackExpressionValue(N, arg, *report);

View File

@ -34,8 +34,10 @@ namespace {
class VLASizeChecker
: public Checker<check::PreStmt<DeclStmt>,
check::PreStmt<UnaryExprOrTypeTraitExpr>> {
mutable std::unique_ptr<BugType> BT;
mutable std::unique_ptr<BugType> TaintBT;
const BugType BT{this, "Dangerous variable-length array (VLA) declaration"};
const BugType TaintBT{this,
"Dangerous variable-length array (VLA) declaration",
categories::TaintedData};
enum VLASize_Kind { VLA_Garbage, VLA_Zero, VLA_Negative, VLA_Overflow };
/// Check a VLA for validity.
@ -213,17 +215,12 @@ void VLASizeChecker::reportTaintBug(const Expr *SizeE, ProgramStateRef State,
if (!N)
return;
if (!TaintBT)
TaintBT.reset(
new BugType(this, "Dangerous variable-length array (VLA) declaration",
categories::TaintedData));
SmallString<256> buf;
llvm::raw_svector_ostream os(buf);
os << "Declared variable-length array (VLA) ";
os << "has tainted size";
auto report = std::make_unique<PathSensitiveBugReport>(*TaintBT, os.str(), N);
auto report = std::make_unique<PathSensitiveBugReport>(TaintBT, os.str(), N);
report->addRange(SizeE->getSourceRange());
bugreporter::trackExpressionValue(N, SizeE, *report);
// The vla size may be a complex expression where multiple memory locations
@ -240,11 +237,6 @@ void VLASizeChecker::reportBug(VLASize_Kind Kind, const Expr *SizeE,
if (!N)
return;
if (!BT)
BT.reset(new BugType(this,
"Dangerous variable-length array (VLA) declaration",
categories::LogicError));
SmallString<256> buf;
llvm::raw_svector_ostream os(buf);
os << "Declared variable-length array (VLA) ";
@ -263,7 +255,7 @@ void VLASizeChecker::reportBug(VLASize_Kind Kind, const Expr *SizeE,
break;
}
auto report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
auto report = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N);
report->addRange(SizeE->getSourceRange());
bugreporter::trackExpressionValue(N, SizeE, *report);
C.emitReport(std::move(report));

View File

@ -44,7 +44,7 @@ namespace {
class VforkChecker : public Checker<check::PreCall, check::PostCall,
check::Bind, check::PreStmt<ReturnStmt>> {
mutable std::unique_ptr<BugType> BT;
const BugType BT{this, "Dangerous construct in a vforked process"};
mutable llvm::SmallSet<const IdentifierInfo *, 10> VforkAllowlist;
mutable const IdentifierInfo *II_vfork = nullptr;
@ -123,9 +123,6 @@ bool VforkChecker::isCallExplicitelyAllowed(const IdentifierInfo *II,
void VforkChecker::reportBug(const char *What, CheckerContext &C,
const char *Details) const {
if (ExplodedNode *N = C.generateErrorNode(C.getState())) {
if (!BT)
BT.reset(new BugType(this, "Dangerous construct in a vforked process"));
SmallString<256> buf;
llvm::raw_svector_ostream os(buf);
@ -134,7 +131,7 @@ void VforkChecker::reportBug(const char *What, CheckerContext &C,
if (Details)
os << "; " << Details;
auto Report = std::make_unique<PathSensitiveBugReport>(*BT, os.str(), N);
auto Report = std::make_unique<PathSensitiveBugReport>(BT, os.str(), N);
// TODO: mark vfork call in BugReportVisitor
C.emitReport(std::move(Report));
}

View File

@ -13,6 +13,7 @@ namespace clang {
namespace ento {
namespace categories {
const char *const AppleAPIMisuse = "API Misuse (Apple)";
const char *const CoreFoundationObjectiveC = "Core Foundation/Objective-C";
const char *const LogicError = "Logic error";
const char *const MemoryRefCount =

Some files were not shown because too many files have changed in this diff Show More