Index: cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td =================================================================== --- cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td +++ cfe/trunk/include/clang/StaticAnalyzer/Checkers/Checkers.td @@ -45,7 +45,6 @@ def CplusplusOptIn : Package<"cplusplus">, InPackage; def Valist : Package<"valist">; -def ValistAlpha : Package<"valist">, InPackage, Hidden; def DeadCode : Package<"deadcode">; def DeadCodeAlpha : Package<"deadcode">, InPackage, Hidden; @@ -291,7 +290,7 @@ // Valist checkers. //===----------------------------------------------------------------------===// -let ParentPackage = ValistAlpha in { +let ParentPackage = Valist in { def UninitializedChecker : Checker<"Uninitialized">, HelpText<"Check for usages of uninitialized (or already released) va_lists.">, @@ -305,7 +304,7 @@ HelpText<"Check for va_lists which are copied onto itself.">, DescFile<"ValistChecker.cpp">; -} // end : "alpha.valist" +} // end : "valist" //===----------------------------------------------------------------------===// // Deadcode checkers. Index: cfe/trunk/lib/StaticAnalyzer/Checkers/ValistChecker.cpp =================================================================== --- cfe/trunk/lib/StaticAnalyzer/Checkers/ValistChecker.cpp +++ cfe/trunk/lib/StaticAnalyzer/Checkers/ValistChecker.cpp @@ -54,11 +54,11 @@ void checkDeadSymbols(SymbolReaper &SR, CheckerContext &C) const; private: - const MemRegion *getVAListAsRegion(SVal SV, CheckerContext &C) const; + const MemRegion *getVAListAsRegion(SVal SV, const Expr *VAExpr, + bool &IsSymbolic, CheckerContext &C) const; StringRef getVariableNameFromRegion(const MemRegion *Reg) const; const ExplodedNode *getStartCallSite(const ExplodedNode *N, - const MemRegion *Reg, - CheckerContext &C) const; + const MemRegion *Reg) const; void reportUninitializedAccess(const MemRegion *VAList, StringRef Msg, CheckerContext &C) const; @@ -138,14 +138,21 @@ for (auto FuncInfo : VAListAccepters) { if (!Call.isCalled(FuncInfo.Func)) continue; + bool Symbolic; const MemRegion *VAList = - getVAListAsRegion(Call.getArgSVal(FuncInfo.VAListPos), C); + getVAListAsRegion(Call.getArgSVal(FuncInfo.VAListPos), + Call.getArgExpr(FuncInfo.VAListPos), Symbolic, C); if (!VAList) return; if (C.getState()->contains(VAList)) return; + // We did not see va_start call, but the source of the region is unknown. + // Be conservative and assume the best. + if (Symbolic) + return; + SmallString<80> Errmsg("Function '"); Errmsg += FuncInfo.Func.getFunctionName(); Errmsg += "' is called with an uninitialized va_list argument"; @@ -155,13 +162,45 @@ } } +const MemRegion *ValistChecker::getVAListAsRegion(SVal SV, const Expr *E, + bool &IsSymbolic, + CheckerContext &C) const { + // FIXME: on some platforms CallAndMessage checker finds some instances of + // the uninitialized va_list usages. CallAndMessage checker is disabled in + // the tests so they can verify platform independently those issues. As a + // side effect, this check is required here. + if (SV.isUnknownOrUndef()) + return nullptr; + // TODO: In the future this should be abstracted away by the analyzer. + bool VaListModelledAsArray = false; + if (const auto *Cast = dyn_cast(E)) { + QualType Ty = Cast->getType(); + VaListModelledAsArray = + Ty->isPointerType() && Ty->getPointeeType()->isRecordType(); + } + const MemRegion *Reg = SV.getAsRegion(); + if (const auto *DeclReg = Reg->getAs()) { + if (isa(DeclReg->getDecl())) + Reg = C.getState()->getSVal(SV.castAs()).getAsRegion(); + } + IsSymbolic = Reg && Reg->getAs(); + // Some VarRegion based VA lists reach here as ElementRegions. + const auto *EReg = dyn_cast_or_null(Reg); + return (EReg && VaListModelledAsArray) ? EReg->getSuperRegion() : Reg; +} + void ValistChecker::checkPreStmt(const VAArgExpr *VAA, CheckerContext &C) const { ProgramStateRef State = C.getState(); - SVal VAListSVal = State->getSVal(VAA->getSubExpr(), C.getLocationContext()); - const MemRegion *VAList = getVAListAsRegion(VAListSVal, C); + const Expr *VASubExpr = VAA->getSubExpr(); + SVal VAListSVal = State->getSVal(VASubExpr, C.getLocationContext()); + bool Symbolic; + const MemRegion *VAList = + getVAListAsRegion(VAListSVal, VASubExpr, Symbolic, C); if (!VAList) return; + if (Symbolic) + return; if (!State->contains(VAList)) reportUninitializedAccess( VAList, "va_arg() is called on an uninitialized va_list", C); @@ -183,22 +222,13 @@ N); } -const MemRegion *ValistChecker::getVAListAsRegion(SVal SV, - CheckerContext &C) const { - const MemRegion *Reg = SV.getAsRegion(); - const auto *TReg = dyn_cast_or_null(Reg); - // Some VarRegion based VLAs reach here as ElementRegions. - const auto *EReg = dyn_cast_or_null(TReg); - return EReg ? EReg->getSuperRegion() : TReg; -} - // This function traverses the exploded graph backwards and finds the node where // the va_list is initialized. That node is used for uniquing the bug paths. // It is not likely that there are several different va_lists that belongs to // different stack frames, so that case is not yet handled. -const ExplodedNode *ValistChecker::getStartCallSite(const ExplodedNode *N, - const MemRegion *Reg, - CheckerContext &C) const { +const ExplodedNode * +ValistChecker::getStartCallSite(const ExplodedNode *N, + const MemRegion *Reg) const { const LocationContext *LeakContext = N->getLocationContext(); const ExplodedNode *StartCallNode = N; @@ -252,7 +282,7 @@ BT_leakedvalist->setSuppressOnSink(true); } - const ExplodedNode *StartNode = getStartCallSite(N, Reg, C); + const ExplodedNode *StartNode = getStartCallSite(N, Reg); PathDiagnosticLocation LocUsedForUniqueing; if (const Stmt *StartCallStmt = PathDiagnosticLocation::getStmt(StartNode)) @@ -278,13 +308,17 @@ void ValistChecker::checkVAListStartCall(const CallEvent &Call, CheckerContext &C, bool IsCopy) const { - const MemRegion *VAList = getVAListAsRegion(Call.getArgSVal(0), C); - ProgramStateRef State = C.getState(); + bool Symbolic; + const MemRegion *VAList = + getVAListAsRegion(Call.getArgSVal(0), Call.getArgExpr(0), Symbolic, C); if (!VAList) return; + ProgramStateRef State = C.getState(); + if (IsCopy) { - const MemRegion *Arg2 = getVAListAsRegion(Call.getArgSVal(1), C); + const MemRegion *Arg2 = + getVAListAsRegion(Call.getArgSVal(1), Call.getArgExpr(1), Symbolic, C); if (Arg2) { if (ChecksEnabled[CK_CopyToSelf] && VAList == Arg2) { RegionVector LeakedVALists{VAList}; @@ -292,7 +326,7 @@ reportLeakedVALists(LeakedVALists, "va_list", " is copied onto itself", C, N, true); return; - } else if (!State->contains(Arg2)) { + } else if (!State->contains(Arg2) && !Symbolic) { if (State->contains(VAList)) { State = State->remove(VAList); RegionVector LeakedVALists{VAList}; @@ -321,10 +355,17 @@ void ValistChecker::checkVAListEndCall(const CallEvent &Call, CheckerContext &C) const { - const MemRegion *VAList = getVAListAsRegion(Call.getArgSVal(0), C); + bool Symbolic; + const MemRegion *VAList = + getVAListAsRegion(Call.getArgSVal(0), Call.getArgExpr(0), Symbolic, C); if (!VAList) return; + // We did not see va_start call, but the source of the region is unknown. + // Be conservative and assume the best. + if (Symbolic) + return; + if (!C.getState()->contains(VAList)) { reportUninitializedAccess( VAList, "va_end() is called on an uninitialized va_list", C); Index: cfe/trunk/test/Analysis/valist-uninitialized-no-undef.c =================================================================== --- cfe/trunk/test/Analysis/valist-uninitialized-no-undef.c +++ cfe/trunk/test/Analysis/valist-uninitialized-no-undef.c @@ -0,0 +1,40 @@ +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -analyze -analyzer-checker=core,valist.Uninitialized,valist.CopyToSelf -analyzer-output=text -analyzer-store=region -verify %s + +#include "Inputs/system-header-simulator-for-valist.h" + +// This is called in call_inlined_uses_arg(), +// and the warning is generated during the analysis of call_inlined_uses_arg(). +void inlined_uses_arg(va_list arg) { + (void)va_arg(arg, int); // expected-warning{{va_arg() is called on an uninitialized va_list}} + // expected-note@-1{{va_arg() is called on an uninitialized va_list}} +} + +void call_inlined_uses_arg(int fst, ...) { + va_list va; + inlined_uses_arg(va); // expected-note{{Calling 'inlined_uses_arg'}} +} + +void f6(va_list *fst, ...) { + va_start(*fst, fst); + // FIXME: There should be no warning for this. + (void)va_arg(*fst, int); // expected-warning{{va_arg() is called on an uninitialized va_list}} + // expected-note@-1{{va_arg() is called on an uninitialized va_list}} + va_end(*fst); +} + +void call_vprintf_bad(int isstring, ...) { + va_list va; + vprintf(isstring ? "%s" : "%d", va); // expected-warning{{Function 'vprintf' is called with an uninitialized va_list argument}} + // expected-note@-1{{Function 'vprintf' is called with an uninitialized va_list argument}} + // expected-note@-2{{Assuming 'isstring' is 0}} + // expected-note@-3{{'?' condition is false}} +} + +void call_vsprintf_bad(char *buffer, ...) { + va_list va; + va_start(va, buffer); // expected-note{{Initialized va_list}} + va_end(va); // expected-note{{Ended va_list}} + vsprintf(buffer, "%s %d %d %lf %03d", va); // expected-warning{{Function 'vsprintf' is called with an uninitialized va_list argument}} + // expected-note@-1{{Function 'vsprintf' is called with an uninitialized va_list argument}} +} + Index: cfe/trunk/test/Analysis/valist-uninitialized.c =================================================================== --- cfe/trunk/test/Analysis/valist-uninitialized.c +++ cfe/trunk/test/Analysis/valist-uninitialized.c @@ -1,17 +1,20 @@ -// RUN: %clang_analyze_cc1 -triple x86_64-pc-linux-gnu -analyzer-checker=core,alpha.valist.Uninitialized,alpha.valist.CopyToSelf -analyzer-output=text -analyzer-store=region -verify %s +// RUN: %clang_analyze_cc1 -triple hexagon-unknown-linux -analyzer-checker=core,valist.Uninitialized,valist.CopyToSelf -analyzer-disable-checker=core.CallAndMessage -analyzer-output=text -analyzer-store=region -verify %s +// RUN: %clang_analyze_cc1 -triple x86_64-pc-linux-gnu -analyzer-checker=core,valist.Uninitialized,valist.CopyToSelf -analyzer-disable-checker=core.CallAndMessage -analyzer-output=text -analyzer-store=region -verify %s #include "Inputs/system-header-simulator-for-valist.h" void f1(int fst, ...) { va_list va; - (void)va_arg(va, int); //expected-warning{{va_arg() is called on an uninitialized va_list}} expected-note{{va_arg() is called on an uninitialized va_list}} + (void)va_arg(va, int); // expected-warning{{va_arg() is called on an uninitialized va_list}} + // expected-note@-1{{va_arg() is called on an uninitialized va_list}} } int f2(int fst, ...) { va_list va; va_start(va, fst); // expected-note{{Initialized va_list}} va_end(va); // expected-note{{Ended va_list}} - return va_arg(va, int); //expected-warning{{va_arg() is called on an uninitialized va_list}} expected-note{{va_arg() is called on an uninitialized va_list}} + return va_arg(va, int); // expected-warning{{va_arg() is called on an uninitialized va_list}} + // expected-note@-1{{va_arg() is called on an uninitialized va_list}} } void f3(int fst, ...) { @@ -25,11 +28,13 @@ void f4(int cond, ...) { va_list va; - if (cond) { // expected-note{{Assuming 'cond' is 0}} expected-note{{Taking false branch}} + if (cond) { // expected-note{{Assuming 'cond' is 0}} + // expected-note@-1{{Taking false branch}} va_start(va, cond); (void)va_arg(va,int); } - va_end(va); //expected-warning{{va_end() is called on an uninitialized va_list}} expected-note{{va_end() is called on an uninitialized va_list}} + va_end(va); //expected-warning{{va_end() is called on an uninitialized va_list}} + // expected-note@-1{{va_end() is called on an uninitialized va_list}} } void f5(va_list fst, ...) { @@ -38,13 +43,6 @@ va_end(fst); } // no-warning -//FIXME: this should not cause a warning -void f6(va_list *fst, ...) { - va_start(*fst, fst); - (void)va_arg(*fst, int); //expected-warning{{va_arg() is called on an uninitialized va_list}} expected-note{{va_arg() is called on an uninitialized va_list}} - va_end(*fst); -} - void f7(int *fst, ...) { va_list x; va_list *y = &x; @@ -58,8 +56,9 @@ va_list *y = &x; va_start(*y,fst); // expected-note{{Initialized va_list}} va_end(x); // expected-note{{Ended va_list}} - (void)va_arg(*y, int); //expected-warning{{va_arg() is called on an uninitialized va_list}} expected-note{{va_arg() is called on an uninitialized va_list}} -} // no-warning + (void)va_arg(*y, int); //expected-warning{{va_arg() is called on an uninitialized va_list}} + // expected-note@-1{{va_arg() is called on an uninitialized va_list}} +} // This only contains problems which are handled by varargs.Unterminated. void reinit(int *fst, ...) { @@ -87,48 +86,56 @@ va_start(va, fst); // expected-note{{Initialized va_list}} (void)va_arg(va, int); va_end(va); // expected-note{{Ended va_list}} - (void)va_arg(va, int); //expected-warning{{va_arg() is called on an uninitialized va_list}} expected-note{{va_arg() is called on an uninitialized va_list}} + (void)va_arg(va, int); //expected-warning{{va_arg() is called on an uninitialized va_list}} + // expected-note@-1{{va_arg() is called on an uninitialized va_list}} } void copyself(int fst, ...) { va_list va; va_start(va, fst); // expected-note{{Initialized va_list}} - va_copy(va, va); // expected-warning{{va_list 'va' is copied onto itself}} expected-note{{va_list 'va' is copied onto itself}} + va_copy(va, va); // expected-warning{{va_list 'va' is copied onto itself}} + // expected-note@-1{{va_list 'va' is copied onto itself}} va_end(va); -} // no-warning +} void copyselfUninit(int fst, ...) { va_list va; - va_copy(va, va); // expected-warning{{va_list 'va' is copied onto itself}} expected-note{{va_list 'va' is copied onto itself}} -} // no-warning + va_copy(va, va); // expected-warning{{va_list 'va' is copied onto itself}} + // expected-note@-1{{va_list 'va' is copied onto itself}} +} void copyOverwrite(int fst, ...) { va_list va, va2; va_start(va, fst); // expected-note{{Initialized va_list}} - va_copy(va, va2); // expected-warning{{Initialized va_list 'va' is overwritten by an uninitialized one}} expected-note{{Initialized va_list 'va' is overwritten by an uninitialized one}} -} // no-warning + va_copy(va, va2); // expected-warning{{Initialized va_list 'va' is overwritten by an uninitialized one}} + // expected-note@-1{{Initialized va_list 'va' is overwritten by an uninitialized one}} +} void copyUnint(int fst, ...) { va_list va, va2; - va_copy(va, va2); // expected-warning{{Uninitialized va_list is copied}} expected-note{{Uninitialized va_list is copied}} + va_copy(va, va2); // expected-warning{{Uninitialized va_list is copied}} + // expected-note@-1{{Uninitialized va_list is copied}} } void g1(int fst, ...) { va_list va; - va_end(va); // expected-warning{{va_end() is called on an uninitialized va_list}} expected-note{{va_end() is called on an uninitialized va_list}} + va_end(va); // expected-warning{{va_end() is called on an uninitialized va_list}} + // expected-note@-1{{va_end() is called on an uninitialized va_list}} } void g2(int fst, ...) { va_list va; va_start(va, fst); // expected-note{{Initialized va_list}} va_end(va); // expected-note{{Ended va_list}} - va_end(va); // expected-warning{{va_end() is called on an uninitialized va_list}} expected-note{{va_end() is called on an uninitialized va_list}} + va_end(va); // expected-warning{{va_end() is called on an uninitialized va_list}} + // expected-note@-1{{va_end() is called on an uninitialized va_list}} } void is_sink(int fst, ...) { va_list va; - va_end(va); // expected-warning{{va_end() is called on an uninitialized va_list}} expected-note{{va_end() is called on an uninitialized va_list}} - *((volatile int *)0) = 1; //no-warning + va_end(va); // expected-warning{{va_end() is called on an uninitialized va_list}} + // expected-note@-1{{va_end() is called on an uninitialized va_list}} + *((volatile int *)0) = 1; } // NOTE: this is invalid, as the man page of va_end requires that "Each invocation of va_start() @@ -141,17 +148,6 @@ (void)va_arg(arg, int); } //no-warning -// This is the same function as the previous one, but it is called in call_uses_arg2(), -// and the warning is generated during the analysis of call_uses_arg2(). -void inlined_uses_arg(va_list arg) { - (void)va_arg(arg, int); //expected-warning{{va_arg() is called on an uninitialized va_list}} expected-note{{va_arg() is called on an uninitialized va_list}} -} - -void call_inlined_uses_arg(int fst, ...) { - va_list va; - inlined_uses_arg(va); // expected-note{{Calling 'inlined_uses_arg'}} -} - void call_vprintf_ok(int isstring, ...) { va_list va; va_start(va, isstring); @@ -159,20 +155,24 @@ va_end(va); } //no-warning -void call_vprintf_bad(int isstring, ...) { +void call_some_other_func(int n, ...) { va_list va; - vprintf(isstring ? "%s" : "%d", va); //expected-warning{{Function 'vprintf' is called with an uninitialized va_list argument}} expected-note{{Function 'vprintf' is called with an uninitialized va_list argument}} expected-note{{Assuming 'isstring' is 0}} expected-note{{'?' condition is false}} -} + some_library_function(n, va); +} //no-warning -void call_vsprintf_bad(char *buffer, ...) { - va_list va; - va_start(va, buffer); // expected-note{{Initialized va_list}} - va_end(va); // expected-note{{Ended va_list}} - vsprintf(buffer, "%s %d %d %lf %03d", va); //expected-warning{{Function 'vsprintf' is called with an uninitialized va_list argument}} expected-note{{Function 'vsprintf' is called with an uninitialized va_list argument}} +void inlined_uses_arg_good(va_list arg) { + (void)va_arg(arg, int); } -void call_some_other_func(int n, ...) { +void call_inlined_uses_arg_good(int fst, ...) { va_list va; - some_library_function(n, va); -} //no-warning + va_start(va, fst); + inlined_uses_arg_good(va); + va_end(va); +} +void va_copy_test(va_list arg) { + va_list dst; + va_copy(dst, arg); + va_end(dst); +} Index: cfe/trunk/test/Analysis/valist-unterminated.c =================================================================== --- cfe/trunk/test/Analysis/valist-unterminated.c +++ cfe/trunk/test/Analysis/valist-unterminated.c @@ -1,11 +1,13 @@ -// RUN: %clang_analyze_cc1 -triple x86_64-pc-linux-gnu -analyzer-checker=core,alpha.valist.Unterminated,alpha.valist.CopyToSelf -analyzer-output=text -analyzer-store=region -verify %s +// RUN: %clang_analyze_cc1 -triple hexagon-unknown-linux -analyzer-checker=core,valist.Unterminated,valist.CopyToSelf -analyzer-output=text -analyzer-store=region -verify %s +// RUN: %clang_analyze_cc1 -triple x86_64-pc-linux-gnu -analyzer-checker=core,valist.Unterminated,valist.CopyToSelf -analyzer-output=text -analyzer-store=region -verify %s #include "Inputs/system-header-simulator-for-valist.h" void f1(int fst, ...) { va_list va; va_start(va, fst); // expected-note{{Initialized va_list}} - return; // expected-warning{{Initialized va_list 'va' is leaked}} expected-note{{Initialized va_list 'va' is leaked}} + return; // expected-warning{{Initialized va_list 'va' is leaked}} + // expected-note@-1{{Initialized va_list 'va' is leaked}} } void f2(int fst, ...) { @@ -13,37 +15,42 @@ va_start(va, fst); // expected-note{{Initialized va_list}} va_end(va); // expected-note{{Ended va_list}} va_start(va, fst); // expected-note{{Initialized va_list}} -} // expected-warning{{Initialized va_list 'va' is leaked}} expected-note{{Initialized va_list 'va' is leaked}}} +} // expected-warning{{Initialized va_list 'va' is leaked}} + // expected-note@-1{{Initialized va_list 'va' is leaked}} void f3(int fst, ...) { va_list va, va2; va_start(va, fst); va_copy(va2, va); // expected-note{{Initialized va_list}} - va_end(va); // expected-warning{{Initialized va_list 'va2' is leaked}} expected-note{{Initialized va_list 'va2' is leaked}} + va_end(va); // expected-warning{{Initialized va_list 'va2' is leaked}} + // expected-note@-1{{Initialized va_list 'va2' is leaked}} } void f4(va_list *fst, ...) { va_start(*fst, fst); // expected-note{{Initialized va_list}} - return; // expected-warning{{Initialized va_list is leaked}} expected-note{{Initialized va_list is leaked}} + return; // expected-warning{{Initialized va_list is leaked}} + // expected-note@-1{{Initialized va_list is leaked}} } void f5(va_list fst, ...) { - va_start(fst, fst); - //FIXME: this should cause a warning -} // no-warning + va_start(fst, fst); // expected-note{{Initialized va_list}} +} // expected-warning{{Initialized va_list}} + // expected-note@-1{{Initialized va_list}} void f6(va_list *fst, ...) { va_start(*fst, fst); // expected-note{{Initialized va_list}} (void)va_arg(*fst, int); //FIXME: this should NOT cause a warning - va_end(*fst); // expected-warning{{Initialized va_list is leaked}} expected-note{{Initialized va_list is leaked}} + va_end(*fst); // expected-warning{{Initialized va_list is leaked}} + // expected-note@-1{{Initialized va_list is leaked}} } void f7(int *fst, ...) { va_list x; va_list *y = &x; va_start(*y,fst); // expected-note{{Initialized va_list}} -} // expected-warning{{Initialized va_list 'x' is leaked}} expected-note{{Initialized va_list 'x' is leaked}} +} // expected-warning{{Initialized va_list 'x' is leaked}} + // expected-note@-1{{Initialized va_list 'x' is leaked}} void f8(int *fst, ...) { va_list x; @@ -54,9 +61,12 @@ void reinit(int *fst, ...) { va_list va; - va_start(va, fst); // expected-note{{Initialized va_list}} expected-note{{Initialized va_list}} - va_start(va, fst); // expected-warning{{Initialized va_list 'va' is initialized again}} expected-note{{Initialized va_list 'va' is initialized again}} -} // expected-warning{{Initialized va_list 'va' is leaked}} expected-note{{Initialized va_list 'va' is leaked}} + va_start(va, fst); // expected-note{{Initialized va_list}} + // expected-note@-1{{Initialized va_list}} + va_start(va, fst); // expected-warning{{Initialized va_list 'va' is initialized again}} + // expected-note@-1{{Initialized va_list 'va' is initialized again}} +} // expected-warning{{Initialized va_list 'va' is leaked}} + // expected-note@-1{{Initialized va_list 'va' is leaked}} void reinitOk(int *fst, ...) { va_list va; @@ -69,20 +79,23 @@ void copyself(int fst, ...) { va_list va; va_start(va, fst); // expected-note{{Initialized va_list}} - va_copy(va, va); // expected-warning{{va_list 'va' is copied onto itself}} expected-note{{va_list 'va' is copied onto itself}} + va_copy(va, va); // expected-warning{{va_list 'va' is copied onto itself}} + // expected-note@-1{{va_list 'va' is copied onto itself}} va_end(va); -} // no-warning +} void copyselfUninit(int fst, ...) { va_list va; - va_copy(va, va); // expected-warning{{va_list 'va' is copied onto itself}} expected-note{{va_list 'va' is copied onto itself}} -} // no-warning + va_copy(va, va); // expected-warning{{va_list 'va' is copied onto itself}} + // expected-note@-1{{va_list 'va' is copied onto itself}} +} void copyOverwrite(int fst, ...) { va_list va, va2; va_start(va, fst); // expected-note{{Initialized va_list}} - va_copy(va, va2); // expected-warning{{Initialized va_list 'va' is overwritten by an uninitialized one}} expected-note{{Initialized va_list 'va' is overwritten by an uninitialized one}} -} // no-warning + va_copy(va, va2); // expected-warning{{Initialized va_list 'va' is overwritten by an uninitialized one}} + // expected-note@-1{{Initialized va_list 'va' is overwritten by an uninitialized one}} +} //This only generates a warning for the valist.Uninitialized checker void copyUnint(int fst, ...) { @@ -94,20 +107,27 @@ va_list va, va2; va_start(va, fst); va_copy(va2, va); // expected-note{{Initialized va_list}} - va_copy(va2, va); // expected-warning{{Initialized va_list 'va2' is initialized again}} expected-note{{Initialized va_list 'va2' is initialized again}} + va_copy(va2, va); // expected-warning{{Initialized va_list 'va2' is initialized again}} + // expected-note@-1{{Initialized va_list 'va2' is initialized again}} va_end(va); va_end(va2); -} //no-warning +} void doublemsg(int fst, ...) { va_list va, va2; - va_start(va, fst), va_start(va2, fst); // expected-warning{{Initialized va_list 'va' is leaked}} expected-warning{{Initialized va_list 'va2' is leaked}} expected-note{{Initialized va_list}} expected-note{{Initialized va_list}} expected-note{{Initialized va_list}} expected-note{{Initialized va_list 'va' is leaked}} + va_start(va, fst), va_start(va2, fst); // expected-warning{{Initialized va_list 'va' is leaked}} + // expected-warning@-1{{Initialized va_list 'va2' is leaked}} + // expected-note@-2{{Initialized va_list}} + // expected-note@-3{{Initialized va_list}} + // expected-note@-4{{Initialized va_list}} + // expected-note@-5{{Initialized va_list 'va' is leaked}} } void in_array(int fst, ...) { va_list va_array[8]; va_start(va_array[3], fst); // expected-note{{Initialized va_list}} -} // expected-warning{{Initialized va_list 'va_array[3]' is leaked}} expected-note{{Initialized va_list 'va_array[3]' is leaked}} +} // expected-warning{{Initialized va_list 'va_array[3]' is leaked}} + // expected-note@-1{{Initialized va_list 'va_array[3]' is leaked}} struct containing_a_valist { va_list vafield; @@ -117,12 +137,14 @@ void in_struct(int fst, ...) { struct containing_a_valist s; va_start(s.vafield, fst); // expected-note{{Initialized va_list}} -} // expected-warning{{Initialized va_list 's.vafield' is leaked}} expected-note{{Initialized va_list 's.vafield' is leaked}} +} // expected-warning{{Initialized va_list 's.vafield' is leaked}} + // expected-note@-1{{Initialized va_list 's.vafield' is leaked}} void casting(int fst, ...) { char mem[sizeof(va_list)]; va_start(*(va_list *) mem, fst); // expected-note{{Initialized va_list}} -} // expected-warning{{Initialized va_list 'mem[0]' is leaked}} expected-note{{Initialized va_list 'mem[0]' is leaked}} +} // expected-warning{{Initialized va_list 'mem[0]' is leaked}} + // expected-note@-1{{Initialized va_list 'mem[0]' is leaked}} void castingOk(int fst, ...) {