vasu-the-sharma wrote:

Hi @tonykuttai @hubert-reinterpretcast I've been working on the changes and 
wanted to share the IR comparison to make sure we're on the right track.

### Code Changes

**clang/lib/CodeGen/CGExprAgg.cpp** (2 changes):

```
// Line ~249: RHS check in EmitAggLoadOfLValue
- LValue LV = CGF.EmitLValue(E);
+ LValue LV = CGF.EmitCheckedLValue(E, CodeGenFunction::TCK_Load);

// Line ~1340: LHS check in VisitBinAssign
- LValue LHS = CGF.EmitLValue(E->getLHS());
+ LValue LHS = CGF.EmitCheckedLValue(E->getLHS(), CodeGenFunction::TCK_Store);
```


**clang/lib/CodeGen/CGClass.cpp** (1 change):

```cpp
- LValue Src = EmitLValue(Arg);
+ LValue Src = EmitCheckedLValue(Arg, TCK_Load);
```

**clang/lib/CodeGen/CGExprCXX.cpp** (1 change):

```cpp
- TrivialAssignmentRHS = EmitLValue(CE->getArg(1));
+ TrivialAssignmentRHS = EmitCheckedLValue(CE->getArg(1), TCK_Load);
```

### IR Comparison

I tested with this simple case:
```c
struct Agg { int x; };
void test_lhs(struct Agg *dest) {
  struct Agg local = {0};
  *dest = local;
}
```

**WITHOUT change** (no null/alignment check on dest):
```llvm
define dso_local void @test_lhs(ptr noundef %dest) #0 {
entry:
  %dest.addr = alloca ptr, align 8
  %local = alloca %struct.Agg, align 4
  store ptr %dest, ptr %dest.addr, align 8
  call void @llvm.memset.p0.i64(ptr align 4 %local, i8 0, i64 4, i1 false)
  %0 = load ptr, ptr %dest.addr, align 8
  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %0, ptr align 4 %local, i64 4, 
i1 false)
  ret void
}
```

**WITH change** (null + alignment check on dest before memcpy):
```llvm
define dso_local void @test_lhs(ptr noundef %dest) #0 {
entry:
  %dest.addr = alloca ptr, align 8
  %local = alloca %struct.Agg, align 4
  store ptr %dest, ptr %dest.addr, align 8
  call void @llvm.memset.p0.i64(ptr align 4 %local, i8 0, i64 4, i1 false)
  %0 = load ptr, ptr %dest.addr, align 8
  %1 = icmp ne ptr %0, null, !nosanitize !1
  %2 = ptrtoint ptr %0 to i64, !nosanitize !1
  %3 = and i64 %2, 3, !nosanitize !1
  %4 = icmp eq i64 %3, 0, !nosanitize !1
  %5 = and i1 %1, %4, !nosanitize !1
  br i1 %5, label %cont, label %handler.type_mismatch, !prof !2, !nosanitize !1

handler.type_mismatch:
  call void @__ubsan_handle_type_mismatch_v1_abort(ptr @1, i64 %2) #4, 
!nosanitize !1
  unreachable, !nosanitize !1

cont:
  call void @llvm.memcpy.p0.p0.i64(ptr align 4 %0, ptr align 4 %local, i64 4, 
i1 false)
  ret void
}
```

**UBSan call count (for test_lhs + test_rhs + test_both):**
- Without change: 3 (RHS checks only)
- With change: 5 (LHS + RHS checks)

### Proposed FileCheck Patterns

Based on the IR, I propose using `CHECK-NEXT:` for precise sequential matching:

```
// CHECK-LABEL: define {{.*}}@test_lhs(
// CHECK: [[DEST:%.*]] = load ptr, ptr %dest.addr
// CHECK-NEXT: [[CMP:%.*]] = icmp ne ptr [[DEST]], null, !nosanitize
// CHECK-NEXT: [[INT:%.*]] = ptrtoint ptr [[DEST]] to i64, !nosanitize
// CHECK-NEXT: [[AND:%.*]] = and i64 [[INT]], 3, !nosanitize
// CHECK-NEXT: [[ALIGN:%.*]] = icmp eq i64 [[AND]], 0, !nosanitize
// CHECK-NEXT: [[OK:%.*]] = and i1 [[CMP]], [[ALIGN]], !nosanitize
// CHECK-NEXT: br i1 [[OK]], label %cont, label %handler.type_mismatch
// CHECK: call void @__ubsan_handle_type_mismatch_v1_abort
// CHECK: call void @llvm.memcpy
```

@tonykuttai @hubert-reinterpretcast Does this look correct? Please let me know 
if the patterns need adjustment or if additional test cases are needed. Thanks.

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

Reply via email to