From d6e5fd52f0d8d59a8c1340439c40564d782eb22a Mon Sep 17 00:00:00 2001 From: Jordan Rose Date: Thu, 20 Sep 2012 01:55:32 +0000 Subject: [PATCH] [analyzer] MallocChecker should not do post-call checks on inlined functions. If someone provides their own function called 'strdup', or 'reallocf', or even 'malloc', and we inlined it, the inlining should have given us all the malloc-related information we need. If we then try to attach new information to the return value, we could end up with spurious warnings. llvm-svn: 164276 --- .../StaticAnalyzer/Checkers/MallocChecker.cpp | 3 ++ clang/test/Analysis/malloc-interprocedural.c | 38 ++++++++++++++++++- 2 files changed, 39 insertions(+), 2 deletions(-) diff --git a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp index c036d739dd4d..3a27d5522187 100644 --- a/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp +++ b/clang/lib/StaticAnalyzer/Checkers/MallocChecker.cpp @@ -442,6 +442,9 @@ bool MallocChecker::isFreeFunction(const FunctionDecl *FD, ASTContext &C) const } void MallocChecker::checkPostStmt(const CallExpr *CE, CheckerContext &C) const { + if (C.wasInlined) + return; + const FunctionDecl *FD = C.getCalleeDecl(CE); if (!FD) return; diff --git a/clang/test/Analysis/malloc-interprocedural.c b/clang/test/Analysis/malloc-interprocedural.c index 0ab3a7155858..4aa6b7545c72 100644 --- a/clang/test/Analysis/malloc-interprocedural.c +++ b/clang/test/Analysis/malloc-interprocedural.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -analyze -analyzer-checker=unix.Malloc -analyzer-inline-max-stack-depth=5 -analyzer-inline-max-function-size=6 -verify %s +// RUN: %clang_cc1 -analyze -analyzer-checker=unix.Malloc -analyzer-inline-max-stack-depth=5 -verify %s #include "Inputs/system-header-simulator.h" @@ -9,7 +9,10 @@ void free(void *); void *realloc(void *ptr, size_t size); void *reallocf(void *ptr, size_t size); void *calloc(size_t nmemb, size_t size); -extern void exit(int) __attribute__ ((__noreturn__)); + +void exit(int) __attribute__ ((__noreturn__)); +void *memcpy(void * restrict s1, const void * restrict s2, size_t n); +size_t strlen(const char *); static void my_malloc1(void **d, size_t size) { *d = malloc(size); @@ -96,3 +99,34 @@ int uafAndCallsFooWithEmptyReturn() { fooWithEmptyReturn(12); return *x; // expected-warning {{Use of memory after it is freed}} } + + +// If we inline any of the malloc-family functions, the checker shouldn't also +// try to do additional modeling. +char *strndup(const char *str, size_t n) { + if (!str) + return 0; + + // DO NOT FIX. This is to test that we are actually using the inlined + // behavior! + if (n < 5) + return 0; + + size_t length = strlen(str); + if (length < n) + n = length; + + char *result = malloc(n + 1); + memcpy(result, str, n); + result[n] = '\0'; + return result; +} + +void useStrndup(size_t n) { + if (n == 0) + (void)strndup(0, 20); // no-warning + else if (n < 5) + (void)strndup("hi there", n); // no-warning + else + (void)strndup("hi there", n); // expected-warning{{leak}} +}