mirror of
https://github.com/freebsd/freebsd-src
synced 2024-10-04 15:40:44 +00:00
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:
commit
647cbc5de8
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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")
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -2441,12 +2441,10 @@ 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 nf = NFList in {
|
||||
defvar T = "(Tuple:" # nf # ")";
|
||||
def : RVVBuiltin<"v" # T # "v", T # "v" # T # "vKzv", "csilxfd">;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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 &)>;
|
||||
|
||||
|
|
|
@ -37,7 +37,6 @@
|
|||
namespace clang {
|
||||
namespace interp {
|
||||
|
||||
using APInt = llvm::APInt;
|
||||
using APSInt = llvm::APSInt;
|
||||
|
||||
/// Convert a value to an APValue.
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
Code = Code.ltrim(" \t\v\f\r");
|
||||
}
|
||||
|
||||
SourceLocation currentLocation() {
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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!");
|
||||
|
|
|
@ -6406,12 +6406,10 @@ 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,
|
||||
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()};
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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,12 +671,17 @@ 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"))
|
||||
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 (ArchName.starts_with_insensitive("rv64"))
|
||||
else if (XLen == 64)
|
||||
Target.setArch(llvm::Triple::riscv64);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Target;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
if (!llvm::errorToBool(ParseResult.takeError()))
|
||||
return (*ParseResult)->computeDefaultABI();
|
||||
|
||||
// 3. Choose a default based on the triple
|
||||
|
|
|
@ -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.");
|
||||
|
|
|
@ -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 {
|
||||
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.
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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());
|
||||
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());
|
||||
|
||||
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;
|
||||
|
|
|
@ -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 "";
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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";
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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) &&
|
||||
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) &&
|
||||
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) &&
|
||||
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";
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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()) {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
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()),
|
||||
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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,8 +443,7 @@ IteratorModeling::handleAdvanceLikeFunction(CheckerContext &C,
|
|||
}
|
||||
|
||||
void IteratorModeling::handleComparison(CheckerContext &C, const Expr *CE,
|
||||
SVal RetVal, const SVal &LVal,
|
||||
const SVal &RVal,
|
||||
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
|
||||
|
@ -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);
|
||||
|
|
|
@ -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))),
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 "
|
||||
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);
|
||||
"with malicious code",
|
||||
N);
|
||||
Report->addRange(Call.getArgSourceRange(2));
|
||||
C.emitReport(std::move(Report));
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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>();
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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,11 +165,9 @@ 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 "
|
||||
DivZeroBug,
|
||||
"Value being compared against zero has already been used "
|
||||
"for division",
|
||||
N);
|
||||
|
||||
|
|
|
@ -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,16 +64,14 @@ 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()) {
|
||||
if (!Ctx.getSVal(Condition).isUndef())
|
||||
return;
|
||||
|
||||
// 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 (!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
|
||||
|
@ -88,7 +86,7 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
|
|||
// 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());
|
||||
assert(!N->pred_empty());
|
||||
const Expr *Ex = cast<Expr>(Condition);
|
||||
ExplodedNode *PrevN = *N->pred_begin();
|
||||
ProgramPoint P = PrevN->getLocation();
|
||||
|
@ -102,14 +100,11 @@ void UndefBranchChecker::checkBranchCondition(const Stmt *Condition,
|
|||
Ex = FindIt.FindExpr(Ex);
|
||||
|
||||
// Emit the bug report.
|
||||
auto R = std::make_unique<PathSensitiveBugReport>(
|
||||
*BT, BT->getDescription(), N);
|
||||
auto R = std::make_unique<PathSensitiveBugReport>(BT, BT.getDescription(), N);
|
||||
bugreporter::trackExpressionValue(N, Ex, *R);
|
||||
R->addRange(Ex->getSourceRange());
|
||||
|
||||
Ctx.emitReport(std::move(R));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ento::registerUndefBranchChecker(CheckerManager &mgr) {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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));
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -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
Loading…
Reference in a new issue