================
@@ -0,0 +1,39 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=core -std=c++17 -verify %s
+
+// https://github.com/llvm/llvm-project/issues/210183
+// Don't crash when binding a value that isn't a CompoundVal (e.g. a pointer
+// reinterpreted as an integer via a template-induced round trip) to a region
+// of array type.
+
+// expected-no-diagnostics
+
+template <typename T>
+class Span {
+public:
+  template <int N>
+  Span(T (&arr)[N]) : ptr_(arr) {}
+  T *data() { return ptr_; }
+  T *ptr_;
+};
+
+class Decoder {
+public:
+  template <typename TInput, typename TOutput>
+  auto decodeOne(TInput input, TOutput output) {
+    using InPtr_t = decltype(input.data());
+    InPtr_t inPtr = input.data();
+    using OutPtr_t = decltype(output.data());
+    OutPtr_t outPtr = output.data();
+    int scratch[1];
+    scratch[0] = *inPtr;
+    int value = scratch[0];
+    *outPtr = value;
+  }
+};
+
+void test() {
+  char buffer[1];
+  Span<char> span(buffer);
+  Decoder decoder;
+  decoder.decodeOne(span, span);
+}
----------------
steakhal wrote:

I'm convinced that we could come up with a shorter reproducer. Usually there is 
something to learn from from a shorter repro and this is no difference:
https://godbolt.org/z/43dPY47eq
```c++
template <class T> void clang_analyzer_dump(T);
template <class T> struct Span {
  template <int N>
  Span(T (&arr)[N]) : ptr_(arr) {}
  T *data() { return ptr_; }
  T *ptr_;
};

char *ptr();
char buffer[10];

void test() {
    char *p = Span<char>(buffer).data();

    // Why are these not the same?
    clang_analyzer_dump(buffer); // &Element{buffer,0 S64b,char}
    clang_analyzer_dump(p);      // &buffer

    int v = (int)(long)ptr();
    clang_analyzer_dump(v); // &SymRegion{conj_$4{char *, LC1, S1907, #1}} [as 
32 bit integer]
    // *p = v; // crash
}
```

My question is, why are the dumps of `buffer` and `p` different? To me, the 
ElementRegion layer doesn't really make sense because we already had a typed 
value region of something that knew it's `char`, thus there is no reinterpret 
cast there (that usually needs an ElementRegion layer at offset 0.)

So we have `buffer` and `p` and storing to any of those should not cause a 
crash.
I guess the main difference is that for `buffer` we take a different path and 
try to bind it differently.
My question is, why does it matter what value we are about to store? It 
shouldn't matter.

Finally, what would be the result with your patch of the last dump?

https://github.com/llvm/llvm-project/pull/210200
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to