Author: devnexen Date: Tue Dec 11 10:57:07 2018 New Revision: 348884 URL: http://llvm.org/viewvc/llvm-project?rev=348884&view=rev Log: [analyzer][CStringChecker] evaluate explicit_bzero
- explicit_bzero has limited scope/usage only for security/crypto purposes but is non-optimisable version of memset/0 and bzero. - explicit_memset has similar signature and semantics as memset but is also a non-optimisable version. Reviewers: NoQ Reviewed By: NoQ Differential Revision: https://reviews.llvm.org/D54592 Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp cfe/trunk/test/Analysis/string.c Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp?rev=348884&r1=348883&r2=348884&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Checkers/CStringChecker.cpp Tue Dec 11 10:57:07 2018 @@ -124,6 +124,7 @@ public: 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; // Utility methods std::pair<ProgramStateRef , ProgramStateRef > @@ -158,7 +159,7 @@ public: static bool SummarizeRegion(raw_ostream &os, ASTContext &Ctx, const MemRegion *MR); - static bool memsetAux(const Expr *DstBuffer, const Expr *CharE, + static bool memsetAux(const Expr *DstBuffer, SVal CharE, const Expr *Size, CheckerContext &C, ProgramStateRef &State); @@ -1005,11 +1006,10 @@ bool CStringChecker::SummarizeRegion(raw } } -bool CStringChecker::memsetAux(const Expr *DstBuffer, const Expr *CharE, +bool CStringChecker::memsetAux(const Expr *DstBuffer, SVal CharVal, const Expr *Size, CheckerContext &C, ProgramStateRef &State) { SVal MemVal = C.getSVal(DstBuffer); - SVal CharVal = C.getSVal(CharE); SVal SizeVal = C.getSVal(Size); const MemRegion *MR = MemVal.getAsRegion(); if (!MR) @@ -2184,13 +2184,59 @@ void CStringChecker::evalMemset(CheckerC // According to the values of the arguments, bind the value of the second // argument to the destination buffer and set string length, or just // invalidate the destination buffer. - if (!memsetAux(Mem, CharE, Size, C, State)) + if (!memsetAux(Mem, C.getSVal(CharE), Size, C, State)) return; State = State->BindExpr(CE, LCtx, MemVal); C.addTransition(State); } +void CStringChecker::evalBzero(CheckerContext &C, const CallExpr *CE) const { + if (CE->getNumArgs() != 2) + return; + + CurrentFunctionDescription = "memory clearance function"; + + const Expr *Mem = CE->getArg(0); + const Expr *Size = CE->getArg(1); + SVal Zero = C.getSValBuilder().makeZeroVal(C.getASTContext().IntTy); + + ProgramStateRef State = C.getState(); + + // See if the size argument is zero. + SVal SizeVal = C.getSVal(Size); + QualType SizeTy = Size->getType(); + + ProgramStateRef StateZeroSize, StateNonZeroSize; + std::tie(StateZeroSize, StateNonZeroSize) = + assumeZero(C, State, SizeVal, SizeTy); + + // If the size is zero, there won't be any actual memory access, + // In this case we just return. + if (StateZeroSize && !StateNonZeroSize) { + C.addTransition(StateZeroSize); + return; + } + + // Get the value of the memory area. + SVal MemVal = C.getSVal(Mem); + + // 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; + + if (!memsetAux(Mem, Zero, Size, C, State)) + return; + + C.addTransition(State); +} + static bool isCPPStdLibraryFunction(const FunctionDecl *FD, StringRef Name) { IdentifierInfo *II = FD->getIdentifier(); if (!II) @@ -2224,7 +2270,8 @@ bool CStringChecker::evalCall(const Call evalFunction = &CStringChecker::evalMemcmp; else if (C.isCLibraryFunction(FDecl, "memmove")) evalFunction = &CStringChecker::evalMemmove; - else if (C.isCLibraryFunction(FDecl, "memset")) + else if (C.isCLibraryFunction(FDecl, "memset") || + C.isCLibraryFunction(FDecl, "explicit_memset")) evalFunction = &CStringChecker::evalMemset; else if (C.isCLibraryFunction(FDecl, "strcpy")) evalFunction = &CStringChecker::evalStrcpy; @@ -2262,6 +2309,9 @@ bool CStringChecker::evalCall(const Call evalFunction = &CStringChecker::evalStdCopy; else if (isCPPStdLibraryFunction(FDecl, "copy_backward")) evalFunction = &CStringChecker::evalStdCopyBackward; + else if (C.isCLibraryFunction(FDecl, "bzero") || + C.isCLibraryFunction(FDecl, "explicit_bzero")) + evalFunction = &CStringChecker::evalBzero; // If the callee isn't a string function, let another checker handle it. if (!evalFunction) Modified: cfe/trunk/test/Analysis/string.c URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/string.c?rev=348884&r1=348883&r2=348884&view=diff ============================================================================== --- cfe/trunk/test/Analysis/string.c (original) +++ cfe/trunk/test/Analysis/string.c Tue Dec 11 10:57:07 2018 @@ -1184,11 +1184,14 @@ void strsep_changes_input_string() { } //===----------------------------------------------------------------------=== -// memset() +// memset() / explicit_bzero() / bzero() //===----------------------------------------------------------------------=== void *memset(void *dest, int ch, size_t count); +void bzero(void *dst, size_t count); +void explicit_bzero(void *dest, size_t count); + void *malloc(size_t size); void free(void *); @@ -1383,6 +1386,57 @@ void memset26_upper_UCHAR_MAX() { clang_analyzer_eval(array[4] == 0); // expected-warning{{TRUE}} } +void bzero1_null() { + char *a = NULL; + + bzero(a, 10); // expected-warning{{Null pointer argument in call to memory clearance function}} +} + +void bzero2_char_array_null() { + char str[] = "abcd"; + clang_analyzer_eval(strlen(str) == 4); // expected-warning{{TRUE}} + bzero(str, 2); + clang_analyzer_eval(strlen(str) == 0); // expected-warning{{TRUE}} +} + +void bzero3_char_ptr_null() { + char *str = "abcd"; + clang_analyzer_eval(strlen(str) == 4); // expected-warning{{TRUE}} + bzero(str + 2, 2); + clang_analyzer_eval(strlen(str) == 0); // expected-warning{{FALSE}} +} + +void explicit_bzero1_null() { + char *a = NULL; + + explicit_bzero(a, 10); // expected-warning{{Null pointer argument in call to memory clearance function}} +} + +void explicit_bzero2_clear_mypassword() { + char passwd[7] = "passwd"; + + explicit_bzero(passwd, sizeof(passwd)); // no-warning + + clang_analyzer_eval(strlen(passwd) == 0); // expected-warning{{TRUE}} + clang_analyzer_eval(passwd[0] == '\0'); // expected-warning{{TRUE}} +} + +void explicit_bzero3_out_ofbound() { + char *privkey = (char *)malloc(7); + const char newprivkey[10] = "mysafekey"; + + strcpy(privkey, "random"); + explicit_bzero(privkey, sizeof(newprivkey)); +#ifndef SUPPRESS_OUT_OF_BOUND + // expected-warning@-2 {{Memory clearance function accesses out-of-bound array element}} +#endif + clang_analyzer_eval(privkey[0] == '\0'); +#ifdef SUPPRESS_OUT_OF_BOUND + // expected-warning@-2 {{UNKNOWN}} +#endif + free(privkey); +} + //===----------------------------------------------------------------------=== // FIXMEs //===----------------------------------------------------------------------=== _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits