[clang] [analyzer] Trust base to derived casts for dynamic types (PR #69057)

Balazs Benics via cfe-commits cfe-commits at lists.llvm.org
Mon Nov 6 06:12:55 PST 2023


================
@@ -492,11 +492,13 @@ void check_required_cast() {
 
 void check_cast_behavior(OSObject *obj) {
   OSArray *arr1 = OSDynamicCast(OSArray, obj);
-  clang_analyzer_eval(arr1 == obj); // expected-warning{{TRUE}}
-                                    // expected-note at -1{{TRUE}}
-                                    // expected-note at -2{{Assuming 'arr1' is not equal to 'obj'}}
-                                    // expected-warning at -3{{FALSE}}
-                                    // expected-note at -4   {{FALSE}}
+  clang_analyzer_eval(arr1 == obj); // #check_cast_behavior_1
+  // expected-warning@#check_cast_behavior_1 {{TRUE}}
+  // expected-note@#check_cast_behavior_1    {{TRUE}}
+  // expected-note@#check_cast_behavior_1{{Assuming 'arr1' is equal to 'obj'}}
----------------
steakhal wrote:

I've looked at the exploded-graph before and after the patch, and the values and the branches are all the same. There is only one difference: in the new graph, after the `(OSArray *)` cast in init-expr of the decl, we have the type info bound: `Dynamic Types`:
```
SymRegion{reg_$0<OSObject * obj>} -> OSArray (or a sub-class)
```

Later, when we load for the analyzer_eval, we can see that on the branch where the `safeMetaCast` succeeds, `arr1` and `obj` refers to the same lvalue, thus already proven to be equal.

![image](https://github.com/llvm/llvm-project/assets/6280485/2d2ee01e-b356-43fd-aa24-62b69d08b145)

BTW if I change the test into this, it would pass on both the old and new versions:
```c++
void check_cast_behavior(OSObject *obj) {
  OSArray *arr1 = OSDynamicCast(OSArray, obj);
  if (!arr1) return;
  // expected-note at -1 {{'arr1' is non-null}} expected-note at -1 {{Taking false branch}}
  // expected-note at -2 {{'arr1' is non-null}} expected-note at -2 {{Taking false branch}}
  clang_analyzer_eval(arr1 == obj); // expected-warning{{TRUE}} expected-note{{TRUE}}
  OSArray *arr2 = OSRequiredCast(OSArray, obj);
  clang_analyzer_eval(arr2 == obj); // expected-warning{{TRUE}} expected-note{{TRUE}}
}
```
I think this test would describe the behavior for the "cast-succeeds" branch, aka. the branch where `arr1` is non-null. Consequently, I believe this PR would not regress this.

https://github.com/llvm/llvm-project/pull/69057


More information about the cfe-commits mailing list