diff --git a/include/clang/Analysis/CloneDetection.h b/include/clang/Analysis/CloneDetection.h index 3398a1f40af5..1ca3514e69b0 100644 --- a/include/clang/Analysis/CloneDetection.h +++ b/include/clang/Analysis/CloneDetection.h @@ -321,11 +321,11 @@ struct OnlyLargestCloneConstraint { void constrain(std::vector &Result); }; -struct AutoGeneratedCloneConstraint { +struct FilenamePatternConstraint { StringRef IgnoredFilesPattern; std::shared_ptr IgnoredFilesRegex; - AutoGeneratedCloneConstraint(StringRef IgnoredFilesPattern) + FilenamePatternConstraint(StringRef IgnoredFilesPattern) : IgnoredFilesPattern(IgnoredFilesPattern) { IgnoredFilesRegex = std::make_shared("^(" + IgnoredFilesPattern.str() + "$)"); diff --git a/include/clang/Basic/DiagnosticGroups.td b/include/clang/Basic/DiagnosticGroups.td index cf404768472f..36b64a125228 100644 --- a/include/clang/Basic/DiagnosticGroups.td +++ b/include/clang/Basic/DiagnosticGroups.td @@ -149,6 +149,7 @@ def GNUFlexibleArrayUnionMember : DiagGroup<"gnu-flexible-array-union-member">; def GNUFoldingConstant : DiagGroup<"gnu-folding-constant">; def FormatExtraArgs : DiagGroup<"format-extra-args">; def FormatZeroLength : DiagGroup<"format-zero-length">; +def CXX1zCompatMangling : DiagGroup<"c++1z-compat-mangling">; // Warnings for C++1y code which is not compatible with prior C++ standards. def CXXPre14Compat : DiagGroup<"c++98-c++11-compat">; @@ -211,7 +212,8 @@ def CXX14CompatPedantic : DiagGroup<"c++14-compat-pedantic", [CXXPre1zCompatPedantic]>; def CXX1zCompat : DiagGroup<"c++1z-compat", [DeprecatedRegister, - DeprecatedIncrementBool]>; + DeprecatedIncrementBool, + CXX1zCompatMangling]>; def ExitTimeDestructors : DiagGroup<"exit-time-destructors">; def FlexibleArrayExtensions : DiagGroup<"flexible-array-extensions">; diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index aa73a6934518..36b41c35b93d 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -507,7 +507,7 @@ def warn_deprecated_copy_operation : Warning< InGroup, DefaultIgnore; def warn_cxx1z_compat_exception_spec_in_signature : Warning< "mangled name of %0 will change in C++17 due to non-throwing exception " - "specification in function signature">, InGroup; + "specification in function signature">, InGroup; def warn_global_constructor : Warning< "declaration requires a global constructor">, diff --git a/lib/Analysis/CloneDetection.cpp b/lib/Analysis/CloneDetection.cpp index 3b44fab9d74a..e86293a1dd0b 100644 --- a/lib/Analysis/CloneDetection.cpp +++ b/lib/Analysis/CloneDetection.cpp @@ -366,7 +366,7 @@ void OnlyLargestCloneConstraint::constrain( } } -bool AutoGeneratedCloneConstraint::isAutoGenerated(const CloneDetector::CloneGroup &Group) { +bool FilenamePatternConstraint::isAutoGenerated(const CloneDetector::CloneGroup &Group) { std::string Error; if (IgnoredFilesPattern.empty() || Group.empty() || !IgnoredFilesRegex->isValid(Error)) diff --git a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp index 32e3ce9270aa..77c24629d71e 100644 --- a/lib/StaticAnalyzer/Checkers/CStringChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CStringChecker.cpp @@ -120,6 +120,7 @@ class CStringChecker : public Checker< eval::Call, 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; // Utility methods std::pair @@ -1999,6 +2000,54 @@ void CStringChecker::evalStdCopyCommon(CheckerContext &C, C.addTransition(State); } +void CStringChecker::evalMemset(CheckerContext &C, const CallExpr *CE) const { + if (CE->getNumArgs() != 3) + return; + + CurrentFunctionDescription = "memory set function"; + + const Expr *Mem = CE->getArg(0); + const Expr *Size = CE->getArg(2); + ProgramStateRef State = C.getState(); + + // See if the size argument is zero. + const LocationContext *LCtx = C.getLocationContext(); + SVal SizeVal = State->getSVal(Size, LCtx); + QualType SizeTy = Size->getType(); + + ProgramStateRef StateZeroSize, StateNonZeroSize; + std::tie(StateZeroSize, StateNonZeroSize) = + assumeZero(C, State, SizeVal, SizeTy); + + // Get the value of the memory area. + SVal MemVal = State->getSVal(Mem, LCtx); + + // If the size is zero, there won't be any actual memory access, so + // just bind the return value to the Mem buffer and return. + if (StateZeroSize && !StateNonZeroSize) { + StateZeroSize = StateZeroSize->BindExpr(CE, LCtx, MemVal); + C.addTransition(StateZeroSize); + return; + } + + // Ensure the memory area is not null. + // If it is NULL there will be a NULL pointer dereference. + State = checkNonNull(C, StateNonZeroSize, Mem, MemVal); + if (!State) + return; + + State = CheckBufferAccess(C, State, Size, Mem); + if (!State) + return; + State = InvalidateBuffer(C, State, Mem, C.getSVal(Mem), + /*IsSourceBuffer*/false, Size); + if (!State) + return; + + State = State->BindExpr(CE, LCtx, MemVal); + C.addTransition(State); +} + static bool isCPPStdLibraryFunction(const FunctionDecl *FD, StringRef Name) { IdentifierInfo *II = FD->getIdentifier(); if (!II) @@ -2032,6 +2081,8 @@ bool CStringChecker::evalCall(const CallExpr *CE, CheckerContext &C) const { evalFunction = &CStringChecker::evalMemcmp; else if (C.isCLibraryFunction(FDecl, "memmove")) evalFunction = &CStringChecker::evalMemmove; + else if (C.isCLibraryFunction(FDecl, "memset")) + evalFunction = &CStringChecker::evalMemset; else if (C.isCLibraryFunction(FDecl, "strcpy")) evalFunction = &CStringChecker::evalStrcpy; else if (C.isCLibraryFunction(FDecl, "strncpy")) diff --git a/lib/StaticAnalyzer/Checkers/CloneChecker.cpp b/lib/StaticAnalyzer/Checkers/CloneChecker.cpp index d0898adf49fb..83955c586b68 100644 --- a/lib/StaticAnalyzer/Checkers/CloneChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/CloneChecker.cpp @@ -82,7 +82,7 @@ void CloneChecker::checkEndOfTranslationUnit(const TranslationUnitDecl *TU, std::vector AllCloneGroups; Detector.findClones(AllCloneGroups, - AutoGeneratedCloneConstraint(IgnoredFilesPattern), + FilenamePatternConstraint(IgnoredFilesPattern), RecursiveCloneTypeIIConstraint(), MinComplexityConstraint(MinComplexity), MinGroupSizeConstraint(2), OnlyLargestCloneConstraint()); diff --git a/test/Analysis/null-deref-ps-region.c b/test/Analysis/null-deref-ps-region.c index 6ef99ae473ca..c46ca6c52ae3 100644 --- a/test/Analysis/null-deref-ps-region.c +++ b/test/Analysis/null-deref-ps-region.c @@ -1,6 +1,11 @@ -// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core -std=gnu99 -analyzer-store=region -verify %s -// expected-no-diagnostics +// RUN: %clang_analyze_cc1 -analyzer-checker=core,alpha.core,unix,alpha.unix -std=gnu99 -analyzer-store=region -verify %s +#include "Inputs/system-header-simulator.h" + +typedef __typeof(sizeof(int)) size_t; +void *memset(void *__s, int __c, size_t __n); +void *malloc(size_t __size); +void free(void *__ptr); // The store for 'a[1]' should not be removed mistakenly. SymbolicRegions may // also be live roots. @@ -13,3 +18,55 @@ void f14(int *a) { i = *p; // no-warning } } + +void foo() { + int *x = malloc(sizeof(int)); + memset(x, 0, sizeof(int)); + int n = 1 / *x; // FIXME: no-warning + free(x); +} + +void bar() { + int *x = malloc(sizeof(int)); + memset(x, 0, 1); + int n = 1 / *x; // no-warning + free(x); +} + +void testConcreteNull() { + int *x = 0; + memset(x, 0, 1); // expected-warning {{Null pointer argument in call to memory set function}} +} + +void testStackArray() { + char buf[13]; + memset(buf, 0, 1); // no-warning +} + +void testHeapSymbol() { + char *buf = (char *)malloc(13); + memset(buf, 0, 1); // no-warning + free(buf); +} + +void testStackArrayOutOfBound() { + char buf[1]; + memset(buf, 0, 1024); // expected-warning {{Memory set function accesses out-of-bound array element}} +} + +void testHeapSymbolOutOfBound() { + char *buf = (char *)malloc(1); + memset(buf, 0, 1024); // expected-warning {{Memory set function accesses out-of-bound array element}} + free(buf); +} + +void testStackArraySameSize() { + char buf[1]; + memset(buf, 0, sizeof(buf)); // no-warning +} + +void testHeapSymbolSameSize() { + char *buf = (char *)malloc(1); + memset(buf, 0, 1); // no-warning + free(buf); +} diff --git a/test/SemaCXX/cxx1z-noexcept-function-type.cpp b/test/SemaCXX/cxx1z-noexcept-function-type.cpp index 40dc3a22e530..524ea8e53c10 100644 --- a/test/SemaCXX/cxx1z-noexcept-function-type.cpp +++ b/test/SemaCXX/cxx1z-noexcept-function-type.cpp @@ -1,5 +1,6 @@ // RUN: %clang_cc1 -std=c++14 -verify -fexceptions -fcxx-exceptions %s // RUN: %clang_cc1 -std=c++1z -verify -fexceptions -fcxx-exceptions %s -Wno-dynamic-exception-spec +// RUN: %clang_cc1 -std=c++14 -verify -fexceptions -fcxx-exceptions -Wno-c++1z-compat-mangling -DNO_COMPAT_MANGLING %s #if __cplusplus > 201402L @@ -81,7 +82,7 @@ namespace CompatWarning { auto f5() -> void (*)() throw(); auto f6() -> void (&)() throw(); auto f7() -> void (X::*)() throw(); -#if __cplusplus <= 201402L +#if __cplusplus <= 201402L && !defined(NO_COMPAT_MANGLING) // expected-warning@-8 {{mangled name of 'f1' will change in C++17 due to non-throwing exception specification in function signature}} // expected-warning@-8 {{mangled name of 'f2' will change in C++17 due to non-throwing exception specification in function signature}} // expected-warning@-8 {{mangled name of 'f3' will change in C++17 due to non-throwing exception specification in function signature}}