<html><head></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; "><div><div>On Nov 19, 2011, at 9:07 PM, Cyril Roelandt wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><span class="Apple-style-span" style="border-collapse: separate; font-family: Helvetica; font-style: normal; font-variant: normal; font-weight: normal; letter-spacing: normal; line-height: normal; orphans: 2; text-align: -webkit-auto; text-indent: 0px; text-transform: none; white-space: normal; widows: 2; word-spacing: 0px; -webkit-border-horizontal-spacing: 0px; -webkit-border-vertical-spacing: 0px; -webkit-text-decorations-in-effect: none; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px; font-size: medium; ">The code should look a little bit better now. Three different functions are used. The 0-checking and report emission are now two different functions, for I thought they served a different purpose, and that the code would be easier to understand that way.</span></blockquote></div><br><div>Hi Cyril,</div><div><br></div><div>I like this patch. I have a few specific comments inline:</div><div><br></div><div><blockquote type="cite"><div><font class="Apple-style-span" color="#000000">diff --git a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp</font></div><div><font class="Apple-style-span" color="#000000">index e955f9e..6a4d63f 100644</font></div><div><font class="Apple-style-span" color="#000000">--- a/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp</font></div><div><font class="Apple-style-span" color="#000000">+++ b/lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp</font></div><div><font class="Apple-style-span" color="#000000">@@ -36,10 +36,17 @@ public:</font></div><div><font class="Apple-style-span" color="#000000"> </font></div><div><font class="Apple-style-span" color="#000000"> void CheckOpen(CheckerContext &C, const CallExpr *CE) const;</font></div><div><font class="Apple-style-span" color="#000000"> void CheckPthreadOnce(CheckerContext &C, const CallExpr *CE) const;</font></div><div><font class="Apple-style-span" color="#000000">+ void CheckCallocZero(CheckerContext &C, const CallExpr *CE) const;</font></div><div><font class="Apple-style-span" color="#000000"> void CheckMallocZero(CheckerContext &C, const CallExpr *CE) const;</font></div><div><font class="Apple-style-span" color="#000000">+ void CheckReallocZero(CheckerContext &C, const CallExpr *CE) const;</font></div><div><font class="Apple-style-span" color="#000000"> </font></div><div><font class="Apple-style-span" color="#000000"> typedef void (UnixAPIChecker::*SubChecker)(CheckerContext &,</font></div><div><font class="Apple-style-span" color="#000000"> const CallExpr *) const;</font></div><div><font class="Apple-style-span" color="#000000">+private:</font></div><div><font class="Apple-style-span" color="#000000">+ void ReportZeroByteAllocation(CheckerContext &C,</font></div><div><font class="Apple-style-span" color="#000000">+ const ExplodedNode *N,</font></div><div><font class="Apple-style-span" color="#000000">+ const Expr *arg,</font></div><div><font class="Apple-style-span" color="#000000">+ const char *fn_name) const;</font></div><div><font class="Apple-style-span" color="#000000"> };</font></div><div><font class="Apple-style-span" color="#000000"> } //end anonymous namespace</font></div><div><font class="Apple-style-span" color="#000000"> </font></div><div><font class="Apple-style-span" color="#000000">@@ -170,48 +177,138 @@ void UnixAPIChecker::CheckPthreadOnce(CheckerContext &C,</font></div><div><font class="Apple-style-span" color="#000000"> }</font></div><div><font class="Apple-style-span" color="#000000"> </font></div><div><font class="Apple-style-span" color="#000000"> //===----------------------------------------------------------------------===//</font></div><div><font class="Apple-style-span" color="#000000">-// "malloc" with allocation size 0</font></div><div><font class="Apple-style-span" color="#000000">+//"calloc", "malloc" and "realloc" with allocation size 0</font></div></blockquote><div><br></div><div>Very minor: please maintain the space here between the '//' and the first letter.</div><div><br></div><blockquote type="cite"><div><font class="Apple-style-span" color="#000000"> //===----------------------------------------------------------------------===//</font></div><div><font class="Apple-style-span" color="#000000"> </font></div><div><font class="Apple-style-span" color="#000000">+// Fills in trueState and falseState</font></div></blockquote><div><br></div><div>Minor: please follow the LLVM convention of ending comments with a '.'</div><br><blockquote type="cite"><div><font class="Apple-style-span" color="#000000">+static int IsZeroByteAllocation(const ProgramState *state,</font></div><div><font class="Apple-style-span" color="#000000">+ const SVal argVal,</font></div><div><font class="Apple-style-span" color="#000000">+ const ProgramState **trueState,</font></div><div><font class="Apple-style-span" color="#000000">+ const ProgramState **falseState) {</font></div><div><font class="Apple-style-span" color="#000000">+ llvm::tie(*trueState, *falseState) = state->assume(cast<DefinedSVal>(argVal));</font></div><div><font class="Apple-style-span" color="#000000">+ return (*falseState && !*trueState);</font></div><div><font class="Apple-style-span" color="#000000">+}</font></div></blockquote><br></div><div>Please have this method return 'bool'. This is C++. :)</div><div><br></div><div>Also, please have a comment indicate what the return value indicates.</div><div><br></div><div><blockquote type="cite"><div><font class="Apple-style-span" color="#000000">+</font></div><div><font class="Apple-style-span" color="#000000">+// N should be non-null here.</font></div></blockquote><div><br></div><div>Please expand the comments, indicating what this function does.</div><div><br></div><div>Also, instead of having a comment that says "N should be non-null", how about</div><div>using __attribute__((nonnull))?</div><br><blockquote type="cite"><div><font class="Apple-style-span" color="#000000">+void UnixAPIChecker::ReportZeroByteAllocation(CheckerContext &C,</font></div><div><font class="Apple-style-span" color="#000000">+ const ExplodedNode *N,</font></div><div><font class="Apple-style-span" color="#000000">+ const Expr *arg,</font></div><div><font class="Apple-style-span" color="#000000">+ const char *fn_name) const {</font></div><div><font class="Apple-style-span" color="#000000">+ // FIXME: Add reference to CERT advisory, and/or C99 standard in bug</font></div><div><font class="Apple-style-span" color="#000000">+ // output.</font></div><div><font class="Apple-style-span" color="#000000">+ LazyInitialize(BT_mallocZero, "Undefined allocation of 0 bytes");</font></div><div><font class="Apple-style-span" color="#000000">+</font></div><div><font class="Apple-style-span" color="#000000">+ llvm::SmallString<256> S;</font></div><div><font class="Apple-style-span" color="#000000">+ llvm::raw_svector_ostream os(S); </font></div><div><font class="Apple-style-span" color="#000000">+ os << "Call to '" << fn_name << "' has an allocation size of 0 bytes";</font></div><div><font class="Apple-style-span" color="#000000">+ BugReport *report = new BugReport(*BT_mallocZero, os.str(), N);</font></div><div><font class="Apple-style-span" color="#000000">+</font></div><div><font class="Apple-style-span" color="#000000">+ report->addRange(arg->getSourceRange());</font></div><div><font class="Apple-style-span" color="#000000">+ report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N, arg));</font></div><div><font class="Apple-style-span" color="#000000">+ C.EmitReport(report);</font></div><div><font class="Apple-style-span" color="#000000">+}</font></div></blockquote><div><br></div><div>Looks good.</div><br><blockquote type="cite"><div><font class="Apple-style-span" color="#000000">+</font></div><div><font class="Apple-style-span" color="#000000">+void UnixAPIChecker::CheckCallocZero(CheckerContext &C,</font></div><div><font class="Apple-style-span" color="#000000">+ const CallExpr *CE) const {</font></div><div><font class="Apple-style-span" color="#000000">+ if (CE->getNumArgs() != 2)</font></div><div><font class="Apple-style-span" color="#000000">+ return;</font></div><div><font class="Apple-style-span" color="#000000">+</font></div><div><font class="Apple-style-span" color="#000000">+ SVal argVal;</font></div><div><font class="Apple-style-span" color="#000000">+ const Expr *arg;</font></div><div><font class="Apple-style-span" color="#000000">+ const ProgramState *state = C.getState();</font></div><div><font class="Apple-style-span" color="#000000">+ const ProgramState *trueState = NULL, *falseState = NULL;</font></div><div><font class="Apple-style-span" color="#000000">+</font></div><div><font class="Apple-style-span" color="#000000">+ /* Check if one of the arguments is equal to 0 */</font></div><div><font class="Apple-style-span" color="#000000">+ arg = CE->getArg(0);</font></div><div><font class="Apple-style-span" color="#000000">+ argVal = state->getSVal(arg);</font></div></blockquote><div><br></div><div>This is unnecessarily verbose. You can just tie declaration and initialization on one line. All, please use '//' style comments, not /* *..</div><div><br></div><div>For example:</div><div><br></div><div>const ProgramState *state = C.getState();</div><div>const ProgramState *trueState = 0, *falseState = 0;</div><div><br></div><div>// Check if one of the arguments is equal to 0.</div><div>const Expr *arg = CE->getArg(0);</div><div>SVal argVal = state->getSVal(arg);</div><div><br></div><br><blockquote type="cite"><div><font class="Apple-style-span" color="#000000">+ if (argVal.isUnknownOrUndef())</font></div><div><font class="Apple-style-span" color="#000000">+ goto check_snd_arg;</font></div><div><font class="Apple-style-span" color="#000000">+</font></div><div><font class="Apple-style-span" color="#000000">+ if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {</font></div><div><font class="Apple-style-span" color="#000000">+ ExplodedNode *N = C.generateSink(falseState);</font></div><div><font class="Apple-style-span" color="#000000">+ if (!N)</font></div><div><font class="Apple-style-span" color="#000000">+ goto check_snd_arg;</font></div><div><font class="Apple-style-span" color="#000000">+</font></div><div><font class="Apple-style-span" color="#000000">+ UnixAPIChecker::ReportZeroByteAllocation(C, N, arg, "calloc"); </font></div><div><font class="Apple-style-span" color="#000000">+ return;</font></div><div><font class="Apple-style-span" color="#000000">+ }</font></div></blockquote><div><br></div><div>I'm not a huge fan of gotos. They stylistically are problematic in C++. It's okay here, but I still think it is a little gross. You could alternatively have a "do ... while(0)" and use "break" statements instead. It's a little gross as well (to some people), but it is more structured.</div><div><br></div><blockquote type="cite"><div><font class="Apple-style-span" color="#000000">+</font></div><div><font class="Apple-style-span" color="#000000">+check_snd_arg:</font></div><div><font class="Apple-style-span" color="#000000">+ arg = CE->getArg(1);</font></div><div><font class="Apple-style-span" color="#000000">+ argVal = state->getSVal(arg);</font></div><div><font class="Apple-style-span" color="#000000">+ if (argVal.isUnknownOrUndef())</font></div><div><font class="Apple-style-span" color="#000000">+ return;</font></div><div><font class="Apple-style-span" color="#000000">+</font></div><div><font class="Apple-style-span" color="#000000">+ if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {</font></div><div><font class="Apple-style-span" color="#000000">+ ExplodedNode *N = C.generateSink(falseState);</font></div><div><font class="Apple-style-span" color="#000000">+ if (!N)</font></div><div><font class="Apple-style-span" color="#000000">+ return;</font></div></blockquote><blockquote type="cite"><div><font class="Apple-style-span" color="#000000">+</font></div><div><font class="Apple-style-span" color="#000000">+ UnixAPIChecker::ReportZeroByteAllocation(C, N, arg, "calloc"); </font></div></blockquote><div><br></div><div>Why do we need this fully qualified name? Why not just 'ReportZeroByteAllocation()'?</div><br><blockquote type="cite"><div><font class="Apple-style-span" color="#000000">+ return;</font></div><div><font class="Apple-style-span" color="#000000">+ }</font></div></blockquote><div><br></div><div>If we have 'ReportZeroByteAllocation() generate the sink node and do the null check, you could just do:</div><div><br></div><div> if (IsZeroByteAllocation(state, argVal, &trueState, &falseState) {</div><div> UnixAPIChecker::ReportZeroByteAllocation(C, falseState, arg, "calloc");</div><div> return;</div><div> }</div><div><br></div><div>Same thing for the other callsites.</div><br><blockquote type="cite"><div><font class="Apple-style-span" color="#000000">+</font></div><div><font class="Apple-style-span" color="#000000">+ // Assume the the value is non-zero going forward.</font></div><div><font class="Apple-style-span" color="#000000">+ assert(trueState);</font></div><div><font class="Apple-style-span" color="#000000">+ if (trueState != state) {</font></div><div><font class="Apple-style-span" color="#000000">+ C.addTransition(trueState);</font></div><div><font class="Apple-style-span" color="#000000">+ }</font></div></blockquote><div><br></div><div>Can just be made:</div><div> </div><div> if (trueState != state)</div><div> C.addTransition(trueState);</div><div><br></div><div>No need for the extra braces.</div><br><blockquote type="cite"><div><font class="Apple-style-span" color="#000000">+}</font></div><div><font class="Apple-style-span" color="#000000">+</font></div><div><font class="Apple-style-span" color="#000000"> // FIXME: Eventually this should be rolled into the MallocChecker, but this</font></div><div><font class="Apple-style-span" color="#000000"> // check is more basic and is valuable for widespread use.</font></div><div><font class="Apple-style-span" color="#000000"> void UnixAPIChecker::CheckMallocZero(CheckerContext &C,</font></div><div><font class="Apple-style-span" color="#000000"> const CallExpr *CE) const {</font></div><div><font class="Apple-style-span" color="#000000">-</font></div><div><font class="Apple-style-span" color="#000000"> // Sanity check that malloc takes one argument.</font></div><div><font class="Apple-style-span" color="#000000"> if (CE->getNumArgs() != 1)</font></div><div><font class="Apple-style-span" color="#000000"> return;</font></div><div><font class="Apple-style-span" color="#000000"> </font></div><div><font class="Apple-style-span" color="#000000"> // Check if the allocation size is 0.</font></div><div><font class="Apple-style-span" color="#000000"> const ProgramState *state = C.getState();</font></div><div><font class="Apple-style-span" color="#000000">- SVal argVal = state->getSVal(CE->getArg(0));</font></div><div><font class="Apple-style-span" color="#000000">+ const ProgramState *trueState = NULL, *falseState = NULL;</font></div><div><font class="Apple-style-span" color="#000000">+ const Expr *arg = CE->getArg(0);</font></div><div><font class="Apple-style-span" color="#000000">+ SVal argVal = state->getSVal(arg);</font></div><div><font class="Apple-style-span" color="#000000"> </font></div><div><font class="Apple-style-span" color="#000000"> if (argVal.isUnknownOrUndef())</font></div><div><font class="Apple-style-span" color="#000000"> return;</font></div><div><font class="Apple-style-span" color="#000000">- </font></div><div><font class="Apple-style-span" color="#000000">- const ProgramState *trueState, *falseState;</font></div><div><font class="Apple-style-span" color="#000000">- llvm::tie(trueState, falseState) = state->assume(cast<DefinedSVal>(argVal));</font></div><div><font class="Apple-style-span" color="#000000">- </font></div><div><font class="Apple-style-span" color="#000000">+</font></div><div><font class="Apple-style-span" color="#000000"> // Is the value perfectly constrained to zero?</font></div><div><font class="Apple-style-span" color="#000000">- if (falseState && !trueState) {</font></div><div><font class="Apple-style-span" color="#000000">+ if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {</font></div><div><font class="Apple-style-span" color="#000000"> ExplodedNode *N = C.generateSink(falseState);</font></div><div><font class="Apple-style-span" color="#000000">- if (!N)</font></div><div><font class="Apple-style-span" color="#000000">- return;</font></div><div><font class="Apple-style-span" color="#000000">- </font></div><div><font class="Apple-style-span" color="#000000">- // FIXME: Add reference to CERT advisory, and/or C99 standard in bug</font></div><div><font class="Apple-style-span" color="#000000">- // output.</font></div><div><font class="Apple-style-span" color="#000000">+ if (N) {</font></div><div><font class="Apple-style-span" color="#000000">+ UnixAPIChecker::ReportZeroByteAllocation(C, N, arg, "malloc"); </font></div></blockquote><div><br></div>Why do we need this fully qualified name? Why not just 'ReportZeroByteAllocation()'?</div><div><br></div><div><br><blockquote type="cite"><div><font class="Apple-style-span" color="#000000">+ }</font></div><div><font class="Apple-style-span" color="#000000">+ return;</font></div></blockquote><div><br></div><div>Same comment as before. If we have ReportZeroByteAllocation() do the generation of the node, you can compress this code. </div><br><blockquote type="cite"><div><font class="Apple-style-span" color="#000000">+ }</font></div><div><font class="Apple-style-span" color="#000000">+ // Assume the the value is non-zero going forward.</font></div><div><font class="Apple-style-span" color="#000000">+ assert(trueState);</font></div><div><font class="Apple-style-span" color="#000000">+ if (trueState != state) {</font></div><div><font class="Apple-style-span" color="#000000">+ C.addTransition(trueState);</font></div><div><font class="Apple-style-span" color="#000000">+ }</font></div></blockquote><div><br></div><div>Ditch the extra braces.</div><br><blockquote type="cite"><div><font class="Apple-style-span" color="#000000">+}</font></div><div><font class="Apple-style-span" color="#000000"> </font></div><div><font class="Apple-style-span" color="#000000">- LazyInitialize(BT_mallocZero, "Undefined allocation of 0 bytes");</font></div><div><font class="Apple-style-span" color="#000000">- </font></div><div><font class="Apple-style-span" color="#000000">- BugReport *report =</font></div><div><font class="Apple-style-span" color="#000000">- new BugReport(*BT_mallocZero, "Call to 'malloc' has an allocation"</font></div><div><font class="Apple-style-span" color="#000000">- " size of 0 bytes", N);</font></div><div><font class="Apple-style-span" color="#000000">- report->addRange(CE->getArg(0)->getSourceRange());</font></div><div><font class="Apple-style-span" color="#000000">- report->addVisitor(bugreporter::getTrackNullOrUndefValueVisitor(N,</font></div><div><font class="Apple-style-span" color="#000000">- CE->getArg(0)));</font></div><div><font class="Apple-style-span" color="#000000">- C.EmitReport(report);</font></div><div><font class="Apple-style-span" color="#000000">+void UnixAPIChecker::CheckReallocZero(CheckerContext &C,</font></div><div><font class="Apple-style-span" color="#000000">+ const CallExpr *CE) const {</font></div><div><font class="Apple-style-span" color="#000000">+ if (CE->getNumArgs() != 2)</font></div><div><font class="Apple-style-span" color="#000000">+ return;</font></div><div><font class="Apple-style-span" color="#000000">+</font></div><div><font class="Apple-style-span" color="#000000">+ const ProgramState *state = C.getState();</font></div><div><font class="Apple-style-span" color="#000000">+ const ProgramState *trueState = NULL, *falseState = NULL;</font></div><div><font class="Apple-style-span" color="#000000">+ const Expr *arg = CE->getArg(1);</font></div><div><font class="Apple-style-span" color="#000000">+ SVal argVal = state->getSVal(arg);</font></div><div><font class="Apple-style-span" color="#000000">+</font></div><div><font class="Apple-style-span" color="#000000">+ if (argVal.isUnknownOrUndef())</font></div><div><font class="Apple-style-span" color="#000000">+ return;</font></div><div><font class="Apple-style-span" color="#000000">+</font></div><div><font class="Apple-style-span" color="#000000">+</font></div></blockquote><div><br></div><div>We don't need two blank lines.</div><br><blockquote type="cite"><div><font class="Apple-style-span" color="#000000">+ if (IsZeroByteAllocation(state, argVal, &trueState, &falseState)) {</font></div><div><font class="Apple-style-span" color="#000000">+ ExplodedNode *N = C.generateSink(falseState);</font></div><div><font class="Apple-style-span" color="#000000">+ if (N) {</font></div><div><font class="Apple-style-span" color="#000000">+ UnixAPIChecker::ReportZeroByteAllocation(C, N, arg, "realloc");</font></div><div><font class="Apple-style-span" color="#000000">+ }</font></div><div><font class="Apple-style-span" color="#000000"> return;</font></div></blockquote><div><br></div><div>Per comment above, this can be made more condensed by sinking the node generation into ReportZeroByteAllocation().</div><br><blockquote type="cite"><div><font class="Apple-style-span" color="#000000"> }</font></div><div><font class="Apple-style-span" color="#000000">+</font></div><div><font class="Apple-style-span" color="#000000"> // Assume the the value is non-zero going forward.</font></div><div><font class="Apple-style-span" color="#000000"> assert(trueState);</font></div><div><font class="Apple-style-span" color="#000000"> if (trueState != state) {</font></div><div><font class="Apple-style-span" color="#000000">@@ -232,7 +329,9 @@ void UnixAPIChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {</font></div><div><font class="Apple-style-span" color="#000000"> llvm::StringSwitch<SubChecker>(FName)</font></div><div><font class="Apple-style-span" color="#000000"> .Case("open", &UnixAPIChecker::CheckOpen)</font></div><div><font class="Apple-style-span" color="#000000"> .Case("pthread_once", &UnixAPIChecker::CheckPthreadOnce)</font></div><div><font class="Apple-style-span" color="#000000">+ .Case("calloc", &UnixAPIChecker::CheckCallocZero)</font></div><div><font class="Apple-style-span" color="#000000"> .Case("malloc", &UnixAPIChecker::CheckMallocZero)</font></div><div><font class="Apple-style-span" color="#000000">+ .Case("realloc", &UnixAPIChecker::CheckReallocZero)</font></div><div><font class="Apple-style-span" color="#000000"> .Default(NULL);</font></div><div><font class="Apple-style-span" color="#000000"> </font></div><div><font class="Apple-style-span" color="#000000"> if (SC)</font></div><div><font class="Apple-style-span" color="#000000">diff --git a/test/Analysis/unix-fns.c b/test/Analysis/unix-fns.c</font></div><div><font class="Apple-style-span" color="#000000">index cf5ca81..86b95c6 100644</font></div><div><font class="Apple-style-span" color="#000000">--- a/test/Analysis/unix-fns.c</font></div><div><font class="Apple-style-span" color="#000000">+++ b/test/Analysis/unix-fns.c</font></div><div><font class="Apple-style-span" color="#000000">@@ -9,7 +9,9 @@ typedef __darwin_pthread_once_t pthread_once_t;</font></div><div><font class="Apple-style-span" color="#000000"> int pthread_once(pthread_once_t *, void (*)(void));</font></div><div><font class="Apple-style-span" color="#000000"> typedef long unsigned int __darwin_size_t;</font></div><div><font class="Apple-style-span" color="#000000"> typedef __darwin_size_t size_t;</font></div><div><font class="Apple-style-span" color="#000000">+void *calloc(size_t, size_t);</font></div><div><font class="Apple-style-span" color="#000000"> void *malloc(size_t);</font></div><div><font class="Apple-style-span" color="#000000">+void *realloc(void *, size_t);</font></div><div><font class="Apple-style-span" color="#000000"> </font></div><div><font class="Apple-style-span" color="#000000"> typedef void (^dispatch_block_t)(void);</font></div><div><font class="Apple-style-span" color="#000000"> typedef long dispatch_once_t;</font></div><div><font class="Apple-style-span" color="#000000">@@ -66,3 +68,33 @@ void pr2899_nowarn(size_t size) {</font></div><div><font class="Apple-style-span" color="#000000"> foo[i] = 0;</font></div><div><font class="Apple-style-span" color="#000000"> }</font></div><div><font class="Apple-style-span" color="#000000"> }</font></div><div><font class="Apple-style-span" color="#000000">+void test_calloc(void) {</font></div><div><font class="Apple-style-span" color="#000000">+ char *foo = calloc(0, 42); // expected-warning{{Call to 'calloc' has an allocation size of 0 bytes}}</font></div><div><font class="Apple-style-span" color="#000000">+ for (unsigned i = 0; i < 100; i++) {</font></div><div><font class="Apple-style-span" color="#000000">+ foo[i] = 0;</font></div><div><font class="Apple-style-span" color="#000000">+ }</font></div><div><font class="Apple-style-span" color="#000000">+}</font></div><div><font class="Apple-style-span" color="#000000">+void test_calloc2(void) {</font></div><div><font class="Apple-style-span" color="#000000">+ char *foo = calloc(42, 0); // expected-warning{{Call to 'calloc' has an allocation size of 0 bytes}}</font></div><div><font class="Apple-style-span" color="#000000">+ for (unsigned i = 0; i < 100; i++) {</font></div><div><font class="Apple-style-span" color="#000000">+ foo[i] = 0;</font></div><div><font class="Apple-style-span" color="#000000">+ }</font></div><div><font class="Apple-style-span" color="#000000">+}</font></div><div><font class="Apple-style-span" color="#000000">+void test_calloc_nowarn(size_t nmemb, size_t size) {</font></div><div><font class="Apple-style-span" color="#000000">+ char *foo = calloc(nmemb, size); // no-warning</font></div><div><font class="Apple-style-span" color="#000000">+ for (unsigned i = 0; i < 100; i++) {</font></div><div><font class="Apple-style-span" color="#000000">+ foo[i] = 0;</font></div><div><font class="Apple-style-span" color="#000000">+ }</font></div><div><font class="Apple-style-span" color="#000000">+}</font></div><div><font class="Apple-style-span" color="#000000">+void test_realloc(char *ptr) {</font></div><div><font class="Apple-style-span" color="#000000">+ char *foo = realloc(ptr, 0); // expected-warning{{Call to 'realloc' has an allocation size of 0 bytes}}</font></div><div><font class="Apple-style-span" color="#000000">+ for (unsigned i = 0; i < 100; i++) {</font></div><div><font class="Apple-style-span" color="#000000">+ foo[i] = 0;</font></div><div><font class="Apple-style-span" color="#000000">+ }</font></div><div><font class="Apple-style-span" color="#000000">+}</font></div><div><font class="Apple-style-span" color="#000000">+void test_realloc_nowarn(char *ptr, size_t size) {</font></div><div><font class="Apple-style-span" color="#000000">+ char *foo = realloc(ptr, size); // no-warning</font></div><div><font class="Apple-style-span" color="#000000">+ for (unsigned i = 0; i < 100; i++) {</font></div><div><font class="Apple-style-span" color="#000000">+ foo[i] = 0;</font></div><div><font class="Apple-style-span" color="#000000">+ }</font></div><div><font class="Apple-style-span" color="#000000">+}</font></div></blockquote><br></div><div>Test cases look good.</div><div><div><br></div></div></body></html>