This patch introduces DynamicCastInfo similar to DynamicTypeInfo which
is stored in CastSets which are storing the dynamic cast informations of
objects based on memory regions. It could be used to store and check the
casts and prevent infeasible paths.
Details
Diff Detail
Event Timeline
@xazax.hun It is somehow performance critical code as we have too many casts in the LLVM. I would really appreciate it if you could review it.
- From now we use a set to store the casts.
- Added a way to dump out the cast informations.
Yay! I understand the rough idea and it looks perfectly reasonable to start with. Please add FIXMEs/TODOs on how we eventually want to support more complicated inheritance hierarchies.
clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h | ||
---|---|---|
4 | Emm, so you're saving successes and failures of all casts regardless of which object is getting casted? That's definitely not sufficient. If X is a Stmt that isn't an Expr, you can't automatically infer that Y is a Stmt that isn't an Expr for any object Y other than X . This information needs to be per-object. Then you'll need to clean it up in checkDeadSymbols. |
clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h | ||
---|---|---|
4 | I have two implementations, the other is set factory based on memory regions. Is it would be a good idea to go through all the regions every time and all their casts to know every possible cast-assumption? I have made it, and I felt like it is overcomplicated as the DynamicTypeMap could be used for asking what is the type now and whether we have better precision and update that information therefore we could update the cast-set as well. |
clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h | ||
---|---|---|
4 | It's about correctness, we don't have much choice here. The current data structure simply cannot work correctly because there's a "one vs many" problem in it: for every pair of types (T₁, T₂) there are *many* possible outcomes of a cast from T₁ to T₂ (depending on the object that's being casted) but the current data structure only has room for *one* such outcome. Your data structure is basically saying "Oh, this shape turned out to be a circle, let's from now on forever believe that triangles don't exist" (?) |
clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h | ||
---|---|---|
4 | Well, let me swap then with the set factory. I think I could handle that in the current shape, but I cannot say no to your clear idea. Thanks for the factory idea! It does the same at the moment. |
I have not decided yet. This only one successful cast allowance is the smallest possible solution, then we need a very great design to do better without exponential path-splitting. I have added a tiny TODO section.
clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicCastInfo.h | ||
---|---|---|
20 | I suggest enum CastResult { Success, Failure } ("a fail" is slang, also "result" because it's basically a result). Also TODO: The success information should ideally go straight into the dynamic type map. | |
32–33 | succeeds(), fails() (valid English). | |
clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicTypeMap.h | ||
0 | Can we move these macros into the cpp file so that they were only accessed by the fancy accessors? Also i don't remember whether these macros do actually work correctly in headers. The original code was doing the trait manually because it had GDMIndex() defined in the cpp file, but if we put these macros into the header we'll have a static variable defined in multiple translation units, which may cause it to have different addresses in different dynamically loaded libraries that include this header. You might need to merge your checkDeadSymbols() into the existing checkDeadSymbols(). | |
clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp | ||
83–93 | Most of the time we should know exactly how many pointer/reference types we need to unwrap. I really prefer we hard-assert this knowledge instead of blindly unwrapping as many pointer/reference types as we want. Because every time we have an unexpected number of unwraps it's an indication that something went horribly wrong. So it's good to have the extra sanity checking. | |
117–131 | To think: in D66423 you added this fancy feature when you dump the current dynamic type of the object instead of the static type. I think this is super cool and we should do it here as well, because the dynamic type is pretty much the only thing that you won't be able to figure out by looking at the source. We could give the same message as for isa, say, Assuming the object is a 'Circle' etc. | |
133 | It would have been much easier for me to read if this variable was called CastInfo. | |
136 | Just CastSucceeds (valid English). | |
clang/lib/StaticAnalyzer/Core/DynamicTypeMap.cpp | ||
18–21 | My favorite way of writing this stuff: const CastSet *SetPtr = State->get<DynamicCastMap>(MR); CastSet Set = SetPtr ? *SetPTr : F.getEmptySet(); |
Also thanks, everything makes sense now!
Do we already have a test that will cover the necessity for having a map from regions to cast results? Eg.:
void foo(Shape *C, Shape *T) { if (isa<Circle>(S) && !isa<Circle>(T)) clang_analyzer_warnIfReached(); // expected-warning{{TRUE}} }
clang/test/Analysis/cast-value-state-dump.cpp | ||
---|---|---|
31 | We're not assuming it, right? We already know it's gonna fail because we already know that it's a circle. |
Something went wrong with message generation, can you take a look?
clang/test/Analysis/cast-value-notes.cpp | ||
---|---|---|
25 | A circle is always a shape. Assuming 'S' is a 'Shape' that is not a 'Circle' sounds about right. Or just Assuming 'S' is not a 'Circle'. | |
35 | A circle is always a circle. | |
56 | The not a 'Circle' part is suspiciously specific. |
- Fix more and publish the previously forgotten comments.
clang/include/clang/StaticAnalyzer/Core/PathSensitive/DynamicCastInfo.h | ||
---|---|---|
20 | The successful cast is going to the type map, and the failure will not. Why would we need to store the failing casts in the type map? Therefore no differentiation is necessary I believe so that nor TODO. | |
clang/test/Analysis/cast-value-state-dump.cpp | ||
31 | We have no knowledge what is what. At the top we see that: Shape -> Circle, and then Triangle -> Circle is something new, so we have to assume that. It is an implementation detail we are allowing only one cast to be succeed. From the user point of view it is an assumption as the current state of the checker could not provide more/better information. It is the same logic from the ConditionBRVisitor. |
clang/test/Analysis/cast-value-notes.cpp | ||
---|---|---|
35 | I have removed that contradiction test case as being silly, but yes, that was the no-warning test properly. |
Thanks!! Here's the last couple of nits that i have.
clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp | ||
---|---|---|
83–93 | I think this one is still forgotten. Maybe a FIXME? | |
95–111 | I'm worried that this may occasionally get too long and/or contain line breaks. Let's do the usual pattern matching instead: say 'X' for a DeclRefExpr to 'X', say 'field Y' for a MemberExpr made with field 'Y', say "the object" in other cases. |
clang/test/Analysis/cast-value-state-dump.cpp | ||
---|---|---|
31 | Yeah, but it's not the observable behavior we'll be trying to preserve, so i suggest a FIXME. |
clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp | ||
---|---|---|
126 | "The" should be capitalized if there's no "Assuming" before it. |
clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp | ||
---|---|---|
83–93 | Now I pattern-match that rule in the evalCall(), therefore we cannot try to evaluate nested references. Would you like to see more checks? |
Let's land this then!~~
clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp | ||
---|---|---|
83–93 | Oh, i see, you removed the recursion. Great. |
Thanks for the review! The build-bots will fire with that QualType fix (1028 TU on its own). I will look into the exploded-graph-rewriter.py after GSoC to fix every stuff like that patch and also invoke my HTML simplification idea.
clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp | ||
---|---|---|
83–93 | I was dumb enough to do not publish my comment six times, sorry. |
It looks like this renamed DynamicTypeMap.h but didn't update all users, see all the files in Checkers at http://llvm-cs.pcc.me.uk/?q=include.*dynamictypemap.h for example.
Which targets did you try to build locally?
See e.g. http://lab.llvm.org:8011/builders/sanitizer-x86_64-linux-gn/builds/4344/steps/ninja%20/logs/stdio for errors; I'm guessing most other bots on http://lab.llvm.org:8011/console will turn red in a bit too.
Well, the errors are in the Static Analyzer, and I have not got any warnings, but now I realized that this header has plenty of injections. Thanks for the fast response! I have fixed it in rL369607.
Thanks! Looks like it builds fine now, but the tests are failing: http://lab.llvm.org:8011/builders/llvm-clang-x86_64-expensive-checks-win/builds/19297/steps/test-check-all/logs/stdio
FAIL: Clang :: Analysis/cast-value-state-dump.cpp (4352 of 48515) ******************** TEST 'Clang :: Analysis/cast-value-state-dump.cpp' FAILED ******************** Script: -- : 'RUN: at line 1'; c:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\build\bin\clang.exe -cc1 -internal-isystem c:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\build\lib\clang\10.0.0\include -nostdsysteminc -analyze -analyzer-constraints=range -analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection -analyzer-output=text -verify C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-state-dump.cpp 2>&1 | c:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\build\bin\filecheck.exe C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-state-dump.cpp -- Exit Code: 1 Command Output (stdout): -- $ ":" "RUN: at line 1" $ "c:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\build\bin\clang.exe" "-cc1" "-internal-isystem" "c:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\build\lib\clang\10.0.0\include" "-nostdsysteminc" "-analyze" "-analyzer-constraints=range" "-analyzer-checker=core,apiModeling.llvm.CastValue,debug.ExprInspection" "-analyzer-output=text" "-verify" "C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-state-dump.cpp" note: command had no output on stdout or stderr error: command failed with exit status: 1 $ "c:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\build\bin\filecheck.exe" "C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-state-dump.cpp" -- ******************** PASS: Clang :: Analysis/castexpr-callback.c (4353 of 48515) PASS: Clang :: Analysis/bool-assignment.c (4354 of 48515) PASS: Clang :: Analysis/builtin-functions.cpp (4355 of 48515) PASS: Clang :: Analysis/cfg-indirect-goto-determinism.cpp (4356 of 48515) PASS: Clang :: Analysis/casts.m (4357 of 48515) FAIL: Clang :: Analysis/cast-value-notes.cpp (4358 of 48515) ******************** TEST 'Clang :: Analysis/cast-value-notes.cpp' FAILED ******************** Script: -- : 'RUN: at line 1'; c:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\build\bin\clang.exe -cc1 -internal-isystem c:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\build\lib\clang\10.0.0\include -nostdsysteminc -analyze -analyzer-constraints=range -analyzer-checker=core,apiModeling.llvm.CastValue -analyzer-output=text -verify C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp -- Exit Code: 1 Command Output (stdout): -- $ ":" "RUN: at line 1" $ "c:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\build\bin\clang.exe" "-cc1" "-internal-isystem" "c:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\build\lib\clang\10.0.0\include" "-nostdsysteminc" "-analyze" "-analyzer-constraints=range" "-analyzer-checker=core,apiModeling.llvm.CastValue" "-analyzer-output=text" "-verify" "C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp" # command stderr: error: 'note' diagnostics expected but not seen: File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 23 (directive at C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp:24): Assuming 'S' is not a 'Circle' File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 30 (directive at C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp:31): Assuming 'S' is a 'Circle' File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 34 (directive at C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp:35): 'C' is a 'Circle' File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 40 (directive at C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp:41): Assuming 'C' is not a 'Triangle' File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 46 (directive at C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp:47): 'C' is not a 'Triangle' File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 59 (directive at C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp:60): 'S' is a 'Circle' File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 63 (directive at C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp:64): 'C' is a 'Triangle' File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 76 (directive at C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp:77): Assuming 'S' is not a 'Circle' File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 79 (directive at C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp:80): Assuming 'S' is a 'Triangle' File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 103 (directive at C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp:104): 'S' is a 'Circle' File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 114 (directive at C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp:115): 'S' is a 'Circle' File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 125 (directive at C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp:126): Assuming 'S' is not a 'Circle' File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 129 (directive at C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp:130): Assuming 'S' is a 'Triangle' File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 135 (directive at C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp:136): 'S' is a 'Triangle' error: 'note' diagnostics seen but not expected: File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 23: h2/ 6aM6 File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 30: h2/ 6a File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 34: h2/ File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 40: h2/06aM6 File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 46: h2/ File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 59: h2/ File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 63: h2/ File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 76: h2/ 6aM6 File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 79: h2/ 6aM6 File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 103: h2/ File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 114: h2/ File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 125: h2/ 6aM6 File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 129: h2/ 6aM6 File C:\ps4-buildslave2\llvm-clang-x86_64-expensive-checks-win\llvm\tools\clang\test\Analysis\cast-value-notes.cpp Line 135: h2/ 28 errors generated. error: command failed with exit status: 1 -- ... Failing Tests (2): Clang :: Analysis/cast-value-notes.cpp Clang :: Analysis/cast-value-state-dump.cpp
I have noticed something is broken other than the first fix, just I am not that professional C++ developer to immediately catch the error. I am totally on it, thanks!
return C.getNoteTag( - [=] { + [=]() -> std::string { SmallString<128> Msg;
That was the fix by rL369609. Somehow it converted to a temporary object therefore that was an issue:
[175/176] Running the Clang regression tests llvm-lit: /b/sanitizer-x86_64-linux-fast/build/llvm/utils/lit/lit/llvm/config.py:340: note: using clang: /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/clang -- Testing: 15399 tests, 64 threads -- Testing: 0 FAIL: Clang :: Analysis/cast-value-notes.cpp (355 of 15399) ******************** TEST 'Clang :: Analysis/cast-value-notes.cpp' FAILED ******************** Script: -- : 'RUN: at line 1'; /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/clang -cc1 -internal-isystem /b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/lib/clang/10.0.0/include -nostdsysteminc -analyze -analyzer-constraints=range -analyzer-checker=core,apiModeling.llvm.CastValue -analyzer-output=text -verify /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/test/Analysis/cast-value-notes.cpp -- Exit Code: 1 Command Output (stderr): -- ================================================================= ==43337==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7fa639ecfa30 at pc 0x000000c7ac85 bp 0x7fff83887490 sp 0x7fff83886c40 READ of size 19 at 0x7fa639ecfa30 thread T0 #0 0xc7ac84 in __asan_memcpy /b/sanitizer-x86_64-linux-fast/build/llvm/projects/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cc:22 #1 0xa328415 in copy /b/sanitizer-x86_64-linux-fast/build/libcxx_build_asan/include/c++/v1/__string:225:50 #2 0xa328415 in __init /b/sanitizer-x86_64-linux-fast/build/libcxx_build_asan/include/c++/v1/string:1792 #3 0xa328415 in basic_string /b/sanitizer-x86_64-linux-fast/build/libcxx_build_asan/include/c++/v1/string:1813 #4 0xa328415 in str /b/sanitizer-x86_64-linux-fast/build/llvm/include/llvm/ADT/StringRef.h:220 #5 0xa328415 in operator basic_string /b/sanitizer-x86_64-linux-fast/build/llvm/include/llvm/ADT/StringRef.h:247 #6 0xa328415 in __call<(lambda at /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/lib/StaticAnalyzer/Checkers/CastValueChecker.cpp:113:7) &> /b/sanitizer-x86_64-linux-fast/build/libcxx_build_asan/include/c++/v1/__functional_base:317 #7 0xa328415 in operator() /b/sanitizer-x86_64-linux-fast/build/libcxx_build_asan/include/c++/v1/functional:1540 #8 0xa328415 in std::__1::__function::__func<getNoteTag(clang::ento::CheckerContext&, clang::ento::DynamicCastInfo const*, clang::QualType, clang::Expr const*, bool, bool)::$_0, std::__1::allocator<getNoteTag(clang::ento::CheckerContext&, clang::ento::DynamicCastInfo const*, clang::QualType, clang::Expr const*, bool, bool)::$_0>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > ()>::operator()() /b/sanitizer-x86_64-linux-fast/build/libcxx_build_asan/include/c++/v1/functional:1714 #9 0xa32751d in operator() /b/sanitizer-x86_64-linux-fast/build/libcxx_build_asan/include/c++/v1/functional:1867:16 #10 0xa32751d in operator() /b/sanitizer-x86_64-linux-fast/build/libcxx_build_asan/include/c++/v1/functional:2473 #11 0xa32751d in operator() /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h:259 #12 0xa32751d in __invoke<(lambda at /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h:259:23) &, clang::ento::BugReporterContext &, clang::ento::BugReport &> /b/sanitizer-x86_64-linux-fast/build/libcxx_build_asan/include/c++/v1/type_traits:3501 #13 0xa32751d in __call<(lambda at /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/include/clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h:259:23) &, clang::ento::BugReporterContext &, clang::ento::BugReport &> /b/sanitizer-x86_64-linux-fast/build/libcxx_build_asan/include/c++/v1/__functional_base:317 #14 0xa32751d in operator() /b/sanitizer-x86_64-linux-fast/build/libcxx_build_asan/include/c++/v1/functional:1540 #15 0xa32751d in std::__1::__function::__func<clang::ento::CheckerContext::getNoteTag(std::__1::function<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > ()>&&, bool)::'lambda'(clang::ento::BugReporterContext&, clang::ento::BugReport&), std::__1::allocator<clang::ento::CheckerContext::getNoteTag(std::__1::function<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > ()>&&, bool)::'lambda'(clang::ento::BugReporterContext&, clang::ento::BugReport&)>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > (clang::ento::BugReporterContext&, clang::ento::BugReport&)>::operator()(clang::ento::BugReporterContext&, clang::ento::BugReport&) /b/sanitizer-x86_64-linux-fast/build/libcxx_build_asan/include/c++/v1/functional:1714 #16 0xa990926 in operator() /b/sanitizer-x86_64-linux-fast/build/libcxx_build_asan/include/c++/v1/functional:1867:16 #17 0xa990926 in operator() /b/sanitizer-x86_64-linux-fast/build/libcxx_build_asan/include/c++/v1/functional:2473 #18 0xa990926 in generateMessage /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/include/clang/StaticAnalyzer/Core/BugReporter/BugReporter.h:572 #19 0xa990926 in clang::ento::TagVisitor::VisitNode(clang::ento::ExplodedNode const*, clang::ento::BugReporterContext&, clang::ento::BugReport&) /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporterVisitors.cpp:2879 #20 0xa94b59f in generateVisitorsDiagnostics(clang::ento::BugReport*, clang::ento::ExplodedNode const*, clang::ento::BugReporterContext&) /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp:2634:19 #21 0xa9417b3 in findValidReport /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp:2674:9 #22 0xa9417b3 in clang::ento::PathSensitiveBugReporter::generatePathDiagnostics(llvm::ArrayRef<clang::ento::PathDiagnosticConsumer*>, llvm::ArrayRef<clang::ento::BugReport*>&) /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp:2708 #23 0xa948006 in clang::ento::BugReporter::generateDiagnosticForConsumerMap(clang::ento::BugReport*, llvm::ArrayRef<clang::ento::PathDiagnosticConsumer*>, llvm::ArrayRef<clang::ento::BugReport*>) /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp:3032:5 #24 0xa93c090 in clang::ento::BugReporter::FlushReport(clang::ento::BugReportEquivClass&) /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp:2893:7 #25 0xa93a72e in clang::ento::BugReporter::FlushReports() /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/lib/StaticAnalyzer/Core/BugReporter.cpp:2308:5 #26 0xa23ec21 in RunPathSensitiveChecks /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:816:24 #27 0xa23ec21 in (anonymous namespace)::AnalysisConsumer::HandleCode(clang::Decl*, unsigned int, clang::ento::ExprEngine::InliningModes, llvm::DenseSet<clang::Decl const*, llvm::DenseMapInfo<clang::Decl const*> >*) /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:774 #28 0xa1f6203 in HandleDeclsCallGraph /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:556:5 #29 0xa1f6203 in runAnalysisOnTranslationUnit /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:607 #30 0xa1f6203 in (anonymous namespace)::AnalysisConsumer::HandleTranslationUnit(clang::ASTContext&) /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp:637 #31 0xad37ae0 in clang::ParseAST(clang::Sema&, bool, bool) /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/lib/Parse/ParseAST.cpp:171:13 #32 0x7ad09b9 in clang::FrontendAction::Execute() /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/lib/Frontend/FrontendAction.cpp:935:8 #33 0x79ae417 in clang::CompilerInstance::ExecuteAction(clang::FrontendAction&) /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/lib/Frontend/CompilerInstance.cpp:946:33 #34 0x7d27c53 in clang::ExecuteCompilerInvocation(clang::CompilerInstance*) /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp:291:25 #35 0xcc5084 in cc1_main(llvm::ArrayRef<char const*>, char const*, void*) /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/tools/driver/cc1_main.cpp:250:15 #36 0xcbcadc in ExecuteCC1Tool /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/tools/driver/driver.cpp:309:12 #37 0xcbcadc in main /b/sanitizer-x86_64-linux-fast/build/llvm/tools/clang/tools/driver/driver.cpp:381 #38 0x7fa63d18f2e0 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x202e0) #39 0xbed7c9 in _start (/b/sanitizer-x86_64-linux-fast/build/llvm_build_asan/bin/clang-10+0xbed7c9) Address 0x7fa639ecfa30 is located in stack of thread T0 at offset 48 in frame #0 0xa32780f in std::__1::__function::__func<getNoteTag(clang::ento::CheckerContext&, clang::ento::DynamicCastInfo const*, clang::QualType, clang::Expr const*, bool, bool)::$_0, std::__1::allocator<getNoteTag(clang::ento::CheckerContext&, clang::ento::DynamicCastInfo const*, clang::QualType, clang::Expr const*, bool, bool)::$_0>, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > ()>::operator()() /b/sanitizer-x86_64-linux-fast/build/libcxx_build_asan/include/c++/v1/functional:1713 This frame has 4 object(s): [32, 176) 'Msg.i.i.i.i' <== Memory access at offset 48 is inside this variable [240, 288) 'Out.i.i.i.i' [320, 344) 'ref.tmp.i.i.i.i' [384, 408) 'ref.tmp14.i.i.i.i' HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork (longjmp and C++ exceptions *are* supported) SUMMARY: AddressSanitizer: stack-use-after-scope /b/sanitizer-x86_64-linux-fast/build/llvm/projects/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cc:22 in __asan_memcpy Shadow bytes around the buggy address: 0x0ff5473d1ef0: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 0x0ff5473d1f00: f1 f1 f1 f1 00 00 00 f2 f2 f2 f2 f2 00 00 00 00 0x0ff5473d1f10: f2 f2 f2 f2 00 00 00 00 f2 f2 f2 f2 f8 f8 f8 f8 0x0ff5473d1f20: f8 f8 f8 f8 f3 f3 f3 f3 00 00 00 00 00 00 00 00 0x0ff5473d1f30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 =>0x0ff5473d1f40: f1 f1 f1 f1 f8 f8[f8]f8 f8 f8 f8 f8 f8 f8 f8 f8 0x0ff5473d1f50: f8 f8 f8 f8 f8 f8 f2 f2 f2 f2 f2 f2 f2 f2 f8 f8 0x0ff5473d1f60: f8 f8 f8 f8 f2 f2 f2 f2 f8 f8 f8 f2 f2 f2 f2 f2 0x0ff5473d1f70: f8 f8 f8 f3 f3 f3 f3 f3 00 00 00 00 00 00 00 00 0x0ff5473d1f80: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 0x0ff5473d1f90: f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 f5 Shadow byte legend (one shadow byte represents 8 application bytes): Addressable: 00 Partially addressable: 01 02 03 04 05 06 07 Heap left redzone: fa Freed heap region: fd Stack left redzone: f1 Stack mid redzone: f2 Stack right redzone: f3 Stack after return: f5 Stack use after scope: f8 Global redzone: f9 Global init order: f6 Poisoned by user: f7 Container overflow: fc Array cookie: ac Intra object redzone: bb ASan internal: fe Left alloca redzone: ca Right alloca redzone: cb Shadow gap: cc ==43337==ABORTING --
Thanks for your notes! Also @xazax.hun may you are interested in this lifetime issue.
I suggest enum CastResult { Success, Failure } ("a fail" is slang, also "result" because it's basically a result).
Also TODO: The success information should ideally go straight into the dynamic type map.