[PATCH] D9912: PR20958 Allow redeclaration of type-generic builtins
ilya-palachev added a comment. Hi! Thanks for this patch. We're building Android6 with Clang (in order to apply static analyzer on it), and without this patch we've 613 build failures. This patch helps to get rid of 521 of those build failures (85%). "Works for me". Comment at: lib/Sema/SemaDecl.cpp:1758 + } + + QualType QT1 = FPT->getParamType(0); Trailing space Comment at: lib/Sema/SemaDecl.cpp:1763 + ArgTypes.push_back(QT2); + + if (QT1->isRealFloatingType() && QT2->isRealFloatingType()) { Ditto Comment at: lib/Sema/SemaDecl.cpp:1775 +<< II->getName() +<< QT1.getAsString(); + return DefaultFunctionType; Ditto Comment at: lib/Sema/SemaDecl.cpp:1837 + case Builtin::BI__builtin_isnan: + case Builtin::BI__builtin_signbit: +Diag(Loc, diag::err_incorrect_args_builtin_redecl) Ditto https://reviews.llvm.org/D9912 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D40073: [Analyzer] Non-determinism: don't sort indirect goto LabelDecl's by addresses
ilya-palachev created this revision. Herald added subscribers: szepet, xazax.hun. Current CFG is built in non-deterministic order due to the fact that indirect goto labels' declarations (LabelDecl's) are stored in the llvm::SmallSet container. LabelDecl's are pointers, whose order is not deterministic by design, and llvm::SmallSet sorts them by their non-deterministic addresses after "small" container is exceeded. This leads to non-deterministic processing of the elements of the container. The fix is to use llvm::SmallSetVector, which is deterministic by design. The introduced test case was creduce'd from Android5 source file. The test file contains 100 runs, in order to make the testing stable: different PLIST's are generated in 20% and 80% cases, correspondingly. Repository: rL LLVM https://reviews.llvm.org/D40073 Files: lib/Analysis/CFG.cpp test/Analysis/diagnostics/goto-label-determinism.cpp Index: test/Analysis/diagnostics/goto-label-determinism.cpp === --- /dev/null +++ test/Analysis/diagnostics/goto-label-determinism.cpp @@ -0,0 +1,254 @@ +// RUN: %clang_analyze_cc1 -triple arm-unknown-linux-gnueabi -w -analyzer-checker=debug.ExprInspection %s -verify +// RUN: for i in {1..100}; do %clang_analyze_cc1 -triple arm-unknown-linux-gnueabi -w -analyzer-checker=debug.ExprInspection -analyzer-config max-nodes=10433 %s -analyzer-output=plist-multi-file -o %t.${i}.plist; done ; for i in {1..100}; do FileCheck --input-file=%t.${i}.plist %s; done ; if [ `md5sum %t.*.plist | awk '{print $1}' | sort -u | wc -l` -gt 1 ] ; then exit 1 ; fi + +int f(); +void clang_analyzer_warnIfReached(); +struct A { + void **t; + int recursion() { +&&L1; +&&L2; +&&L3; +&&L4; +&&L5; +&&L6; +&&L7; +&&L8; +&&L9; + L1: +f() > recursion(); + L2: +goto *t[f()]; + L3: +clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}; + L4: + L5: + L6: + L7: + L8: + L9: +return 0; + } +}; + +// CHECK: diagnostics +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT:start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line9 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line9 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT:end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT:start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT:end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT:start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT:end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +
[PATCH] D40073: [Analyzer] Non-determinism: don't sort indirect goto LabelDecl's by addresses
ilya-palachev updated this revision to Diff 123016. ilya-palachev added a comment. Slightly changed the number of max-nodes, since previous one was maximum possible on my local branch, and it doesn't work for upstream. The behavior with number 500 seems more stable. With it, we have 4 different types of PLIST's being generated: 14, 54, 8 and 24 times, correspondingly. Repository: rL LLVM https://reviews.llvm.org/D40073 Files: lib/Analysis/CFG.cpp test/Analysis/diagnostics/goto-label-determinism.cpp Index: test/Analysis/diagnostics/goto-label-determinism.cpp === --- /dev/null +++ test/Analysis/diagnostics/goto-label-determinism.cpp @@ -0,0 +1,254 @@ +// RUN: %clang_analyze_cc1 -triple arm-unknown-linux-gnueabi -w -analyzer-checker=debug.ExprInspection %s -verify +// RUN: for i in {1..100}; do %clang_analyze_cc1 -triple arm-unknown-linux-gnueabi -w -analyzer-checker=debug.ExprInspection -analyzer-config max-nodes=500 %s -analyzer-output=plist-multi-file -o %t.${i}.plist; done ; for i in {1..100}; do FileCheck --input-file=%t.${i}.plist %s; done ; if [ `md5sum %t.*.plist | awk '{print $1}' | sort -u | wc -l` -gt 1 ] ; then exit 1 ; fi + +int f(); +void clang_analyzer_warnIfReached(); +struct A { + void **t; + int recursion() { +&&L1; +&&L2; +&&L3; +&&L4; +&&L5; +&&L6; +&&L7; +&&L8; +&&L9; + L1: +f() > recursion(); + L2: +goto *t[f()]; + L3: +clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}; + L4: + L5: + L6: + L7: + L8: + L9: +return 0; + } +}; + +// CHECK: diagnostics +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: path +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT:start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line9 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line9 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT:end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT:start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line17 +// CHECK-NEXT: col6 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT:end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT:start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line19 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT:end +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: kindcontrol +// CHECK-NEXT: edges +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT:start +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col5 +// CHECK-NEXT: file0 +// CHECK-NEXT: +// CHECK-NEXT: +// CHECK-NEXT: line21 +// CHECK-NEXT: col8 +// CHECK-NEXT: file0 +// CHECK-NEXT:
[PATCH] D40073: [Analyzer] Non-determinism: don't sort indirect goto LabelDecl's by addresses
ilya-palachev updated this revision to Diff 123558. ilya-palachev added a comment. Ok, I agree, this test file is rather better. https://reviews.llvm.org/D40073 Files: lib/Analysis/CFG.cpp test/Analysis/cfg-indirect-goto-determinism.cpp Index: test/Analysis/cfg-indirect-goto-determinism.cpp === --- /dev/null +++ test/Analysis/cfg-indirect-goto-determinism.cpp @@ -0,0 +1,96 @@ +// RUN: %clang_analyze_cc1 -analyzer-checker=debug.DumpCFG %s 2>&1 | FileCheck %s + +void *target; +int indirectBlockSuccessorDeterminism() { +(void)&&L1; +(void)&&L2; +(void)&&L3; +(void)&&L4; +(void)&&L5; +(void)&&L6; +(void)&&L7; +(void)&&L8; +(void)&&L9; +(void)&&L10; +(void)&&L11; +(void)&&L12; +(void)&&L13; +(void)&&L14; +(void)&&L15; +(void)&&L16; +(void)&&L17; +(void)&&L18; +(void)&&L19; +(void)&&L20; +(void)&&L21; +(void)&&L22; +(void)&&L23; +(void)&&L24; +(void)&&L25; +(void)&&L26; +(void)&&L27; +(void)&&L28; +(void)&&L29; +(void)&&L30; +(void)&&L31; +(void)&&L32; +(void)&&L33; +(void)&&L34; +(void)&&L35; +(void)&&L36; +(void)&&L37; +(void)&&L38; +(void)&&L39; +(void)&&L40; + +goto *target; + L1: + L2: + L3: + L4: + L5: + L6: + L7: + L8: + L9: + L10: + L11: + L12: + L13: + L14: + L15: + L16: + L17: + L18: + L19: + L20: + L21: + L22: + L23: + L24: + L25: + L26: + L27: + L28: + L29: + L30: + L31: + L32: + L33: + L34: + L35: + L36: + L37: + L38: + L39: + L40: +return 0; +} + +// CHECK-LABEL: [B41 (INDIRECT GOTO DISPATCH)] +// CHECK-NEXT: Preds (1): B42 +// CHECK-NEXT: Succs (40): B1 B2 B3 B4 B5 B6 B7 B8 +// CHECK-NEXT: B9 B10 B11 B12 B13 B14 B15 B16 B17 B18 +// CHECK-NEXT: B19 B20 B21 B22 B23 B24 B25 B26 B27 B28 +// CHECK-NEXT: B29 B30 B31 B32 B33 B34 B35 B36 B37 B38 +// CHECK-NEXT: B39 B40 Index: lib/Analysis/CFG.cpp === --- lib/Analysis/CFG.cpp +++ lib/Analysis/CFG.cpp @@ -420,7 +420,7 @@ BackpatchBlocksTy BackpatchBlocks; // A list of labels whose address has been taken (for indirect gotos). - typedef llvm::SmallPtrSet LabelSetTy; + typedef llvm::SmallSetVector LabelSetTy; LabelSetTy AddressTakenLabels; bool badCFG; ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D27710: [analyzer] Prohibit ExplodedGraph's edges duplicating
ilya-palachev added a comment. In https://reviews.llvm.org/D27710#628069, @zaks.anna wrote: > Are there any negative effects from having the duplicates in edges? Yes, you're right; in current implementation there seems to be no negative effects from this, since duplicate edges are quite rare, and they produce very small overhead on memory (just two additional pointers for each excessive edge). > When does this occur? It's a bit suspicious since we have a FromN, and a path > is split at that node, resulting in successors that are the same. Is it > possible that whoever split the state did not encode enough interesting info? Yes, this does occur (for one of our checkers on Android). This patch is more likely a request for comments for what to do in the situation discussed below... Consider the checker that can emit warnings on multiple dead symbols (one warning for each buggy symbol). When the checker encounters such situation, it first emits a warning for the 1st symbol, then for the 2nd one. For the 2nd and other symbols the CheckerContext::addTransition returns `nullptr'. That means that the requested node already exist, because the State hasn't changed. And for each warning beginning from the 2nd, the additional edge is added for the ExplodedGraph. It can be even simply seen with DOT graph. Yes, this problem can be resolved with checker tags for nodes, but in this case we'll need to create new tag for each such warning (because ProgramPoint and ProgramState are equal for them all). Moreover, such cases can even lead to non-determinism in warnings. The checker stores a set(map/list...) of buggy symbols (regions...) in GDM. When checkDeadSymbols callback happens, this set is iterated, and the checker tries to emit a warning for each of them. But actually the order in which symbols are stored in the set depends on their order as pointers, and it's controlled by allocator. The allocator contains non-determinism by design, and region for symbol A can be greater (as a pointer) that the region for the symbol B in one analysis run, and smaller during the another run. That's why in such cases different warnings can be emitted from time to time. The discussed patch doesn't address this issue, but I'd like at least to discuss the situation. Repository: rL LLVM https://reviews.llvm.org/D27710 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D27710: [analyzer] Prohibit ExplodedGraph's edges duplicating
ilya-palachev added a comment. Thanks for review! > As Artem points out, the checkers in tree do not create a node for every bug > reported - there is no reason to do that. Yes... But why does `generateNonFatalErrorNode` return `nullptr` in case when the node already exists? Isn't it designed so that to prevent multiple reports being thrown for the same node? If so, then the code contains a lot of such checks. I don't understand why the following test passes, because each of two checkers: `MallocChecker` and `SimpleStreamChecker` are using `generateNonFatalErrorNode` method: // RUN: %clang_cc1 -analyze -analyzer-checker=unix.Malloc,alpha.unix.SimpleStream -analyzer-store region -verify %s typedef struct _IO_FILE FILE; extern FILE *fopen(const char *path, const char *mode); extern int fclose(FILE *fp); typedef __typeof(sizeof(int)) size_t; void *malloc(size_t); void free(void *); void test() { void *p = malloc(1); void *r = fopen("foo", "r"); if (r) { (void)(p - r); // expected-warning@-1{{Potential leak of memory}} // expected-warning@-2{{Opened file is never closed}} } else { fclose(r); free(p); } } Maybe it's possible to invent such a testcase when two checkers begin to conflict for the node. Or not? Repository: rL LLVM https://reviews.llvm.org/D27710 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D27710: [analyzer] Prohibit ExplodedGraph's edges duplicating
ilya-palachev abandoned this revision. ilya-palachev added a comment. Ok, then, if you see no problem in dual edges, I'm abandoning this revision. Repository: rL LLVM https://reviews.llvm.org/D27710 ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D27710: [analyzer] Prohibit ExplodedGraph's edges duplicating
ilya-palachev created this revision. ilya-palachev added reviewers: NoQ, zaks.anna, dcoughlin. ilya-palachev added subscribers: cfe-commits, a.sidorin, ilya-palachev. ilya-palachev set the repository for this revision to rL LLVM. Current implementation doesn't take care about the duplicates in edges of ExplodedGraph. This actually happens when, for example, the checker tries to add transition to node, and gets `nullptr', which means that the node already exists and has been processed. In this case edge between the node and its predecessor is duplicated. This patch prohibits this situation, by checking whether the actual group already contains the given predecessor. Repository: rL LLVM https://reviews.llvm.org/D27710 Files: lib/StaticAnalyzer/Core/CoreEngine.cpp lib/StaticAnalyzer/Core/ExplodedGraph.cpp Index: lib/StaticAnalyzer/Core/ExplodedGraph.cpp === --- lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -215,6 +215,11 @@ void ExplodedNode::addPredecessor(ExplodedNode *V, ExplodedGraph &G) { assert (!V->isSink()); + for (ExplodedNode *N : Preds) +assert(N != V && "Edge already exists"); + for (ExplodedNode *N : Succs) +assert(N != this && "Edge already exists"); + Preds.addNode(V, G); V->Succs.addNode(this, G); #ifndef NDEBUG Index: lib/StaticAnalyzer/Core/CoreEngine.cpp === --- lib/StaticAnalyzer/Core/CoreEngine.cpp +++ lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -657,7 +657,17 @@ HasGeneratedNodes = true; bool IsNew; ExplodedNode *N = C.Eng.G.getNode(Loc, State, MarkAsSink, &IsNew); - N->addPredecessor(FromN, C.Eng.G); + + bool EdgeExists = false; + for (auto I = N->pred_begin(), E = N->pred_end(); I != E; ++I) +if (*I == FromN) { + EdgeExists = true; + break; +} + + if (!EdgeExists) +N->addPredecessor(FromN, C.Eng.G); + Frontier.erase(FromN); if (!IsNew) Index: lib/StaticAnalyzer/Core/ExplodedGraph.cpp === --- lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -215,6 +215,11 @@ void ExplodedNode::addPredecessor(ExplodedNode *V, ExplodedGraph &G) { assert (!V->isSink()); + for (ExplodedNode *N : Preds) +assert(N != V && "Edge already exists"); + for (ExplodedNode *N : Succs) +assert(N != this && "Edge already exists"); + Preds.addNode(V, G); V->Succs.addNode(this, G); #ifndef NDEBUG Index: lib/StaticAnalyzer/Core/CoreEngine.cpp === --- lib/StaticAnalyzer/Core/CoreEngine.cpp +++ lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -657,7 +657,17 @@ HasGeneratedNodes = true; bool IsNew; ExplodedNode *N = C.Eng.G.getNode(Loc, State, MarkAsSink, &IsNew); - N->addPredecessor(FromN, C.Eng.G); + + bool EdgeExists = false; + for (auto I = N->pred_begin(), E = N->pred_end(); I != E; ++I) +if (*I == FromN) { + EdgeExists = true; + break; +} + + if (!EdgeExists) +N->addPredecessor(FromN, C.Eng.G); + Frontier.erase(FromN); if (!IsNew) ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D27710: [analyzer] Prohibit ExplodedGraph's edges duplicating
ilya-palachev removed rL LLVM as the repository for this revision. ilya-palachev updated this revision to Diff 81221. ilya-palachev added a comment. Fixed a typo https://reviews.llvm.org/D27710 Files: lib/StaticAnalyzer/Core/CoreEngine.cpp lib/StaticAnalyzer/Core/ExplodedGraph.cpp Index: lib/StaticAnalyzer/Core/ExplodedGraph.cpp === --- lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -215,6 +215,11 @@ void ExplodedNode::addPredecessor(ExplodedNode *V, ExplodedGraph &G) { assert (!V->isSink()); + for (ExplodedNode *N : Preds) +assert(N != V && "Edge already exists"); + for (ExplodedNode *N : V->Succs) +assert(N != this && "Edge already exists"); + Preds.addNode(V, G); V->Succs.addNode(this, G); #ifndef NDEBUG Index: lib/StaticAnalyzer/Core/CoreEngine.cpp === --- lib/StaticAnalyzer/Core/CoreEngine.cpp +++ lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -657,7 +657,17 @@ HasGeneratedNodes = true; bool IsNew; ExplodedNode *N = C.Eng.G.getNode(Loc, State, MarkAsSink, &IsNew); - N->addPredecessor(FromN, C.Eng.G); + + bool EdgeExists = false; + for (auto I = N->pred_begin(), E = N->pred_end(); I != E; ++I) +if (*I == FromN) { + EdgeExists = true; + break; +} + + if (!EdgeExists) +N->addPredecessor(FromN, C.Eng.G); + Frontier.erase(FromN); if (!IsNew) Index: lib/StaticAnalyzer/Core/ExplodedGraph.cpp === --- lib/StaticAnalyzer/Core/ExplodedGraph.cpp +++ lib/StaticAnalyzer/Core/ExplodedGraph.cpp @@ -215,6 +215,11 @@ void ExplodedNode::addPredecessor(ExplodedNode *V, ExplodedGraph &G) { assert (!V->isSink()); + for (ExplodedNode *N : Preds) +assert(N != V && "Edge already exists"); + for (ExplodedNode *N : V->Succs) +assert(N != this && "Edge already exists"); + Preds.addNode(V, G); V->Succs.addNode(this, G); #ifndef NDEBUG Index: lib/StaticAnalyzer/Core/CoreEngine.cpp === --- lib/StaticAnalyzer/Core/CoreEngine.cpp +++ lib/StaticAnalyzer/Core/CoreEngine.cpp @@ -657,7 +657,17 @@ HasGeneratedNodes = true; bool IsNew; ExplodedNode *N = C.Eng.G.getNode(Loc, State, MarkAsSink, &IsNew); - N->addPredecessor(FromN, C.Eng.G); + + bool EdgeExists = false; + for (auto I = N->pred_begin(), E = N->pred_end(); I != E; ++I) +if (*I == FromN) { + EdgeExists = true; + break; +} + + if (!EdgeExists) +N->addPredecessor(FromN, C.Eng.G); + Frontier.erase(FromN); if (!IsNew) ___ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits