Skip to content

Commit af694c5

Browse files
committed
[DSE] Use precise loc for memset_chk during overwrite checks
memset_chk may not write the number of bytes specified by the third argument, if it is larger than the destination size (specified as 4th argument). Reviewed By: asbirlea Differential Revision: https://reviews.llvm.org/D115167
1 parent 82a5f1c commit af694c5

File tree

2 files changed

+28
-10
lines changed

2 files changed

+28
-10
lines changed

llvm/lib/Transforms/Scalar/DeadStoreElimination.cpp

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -879,6 +879,26 @@ struct DSEState {
879879
CodeMetrics::collectEphemeralValues(&F, &AC, EphValues);
880880
}
881881

882+
LocationSize strengthenLocationSize(const Instruction *I,
883+
LocationSize Size) const {
884+
if (auto *CB = dyn_cast<CallBase>(I)) {
885+
LibFunc F;
886+
if (TLI.getLibFunc(*CB, F) && TLI.has(F) && F == LibFunc_memset_chk) {
887+
// Use the precise location size specified by the 3rd argument
888+
// for determining KillingI overwrites DeadLoc if it is a memset_chk
889+
// instruction. memset_chk will write either the amount specified as 3rd
890+
// argument or the function will immediately abort and exit the program.
891+
// NOTE: AA may determine NoAlias if it can prove that the access size
892+
// is larger than the allocation size due to that being UB. To avoid
893+
// returning potentially invalid NoAlias results by AA, limit the use of
894+
// the precise location size to isOverwrite.
895+
if (const auto *Len = dyn_cast<ConstantInt>(CB->getArgOperand(2)))
896+
return LocationSize::precise(Len->getZExtValue());
897+
}
898+
}
899+
return Size;
900+
}
901+
882902
/// Return 'OW_Complete' if a store to the 'KillingLoc' location (by \p
883903
/// KillingI instruction) completely overwrites a store to the 'DeadLoc'
884904
/// location (by \p DeadI instruction).
@@ -898,23 +918,25 @@ struct DSEState {
898918
if (!isGuaranteedLoopIndependent(DeadI, KillingI, DeadLoc))
899919
return OW_Unknown;
900920

921+
LocationSize KillingLocSize =
922+
strengthenLocationSize(KillingI, KillingLoc.Size);
901923
const Value *DeadPtr = DeadLoc.Ptr->stripPointerCasts();
902924
const Value *KillingPtr = KillingLoc.Ptr->stripPointerCasts();
903925
const Value *DeadUndObj = getUnderlyingObject(DeadPtr);
904926
const Value *KillingUndObj = getUnderlyingObject(KillingPtr);
905927

906928
// Check whether the killing store overwrites the whole object, in which
907929
// case the size/offset of the dead store does not matter.
908-
if (DeadUndObj == KillingUndObj && KillingLoc.Size.isPrecise()) {
930+
if (DeadUndObj == KillingUndObj && KillingLocSize.isPrecise()) {
909931
uint64_t KillingUndObjSize = getPointerSize(KillingUndObj, DL, TLI, &F);
910932
if (KillingUndObjSize != MemoryLocation::UnknownSize &&
911-
KillingUndObjSize == KillingLoc.Size.getValue())
933+
KillingUndObjSize == KillingLocSize.getValue())
912934
return OW_Complete;
913935
}
914936

915937
// FIXME: Vet that this works for size upper-bounds. Seems unlikely that we'll
916938
// get imprecise values here, though (except for unknown sizes).
917-
if (!KillingLoc.Size.isPrecise() || !DeadLoc.Size.isPrecise()) {
939+
if (!KillingLocSize.isPrecise() || !DeadLoc.Size.isPrecise()) {
918940
// In case no constant size is known, try to an IR values for the number
919941
// of bytes written and check if they match.
920942
const auto *KillingMemI = dyn_cast<MemIntrinsic>(KillingI);
@@ -931,7 +953,7 @@ struct DSEState {
931953
return isMaskedStoreOverwrite(KillingI, DeadI, BatchAA);
932954
}
933955

934-
const uint64_t KillingSize = KillingLoc.Size.getValue();
956+
const uint64_t KillingSize = KillingLocSize.getValue();
935957
const uint64_t DeadSize = DeadLoc.Size.getValue();
936958

937959
// Query the alias information

llvm/test/Transforms/DeadStoreElimination/libcalls-chk.ll

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ declare void @use(ptr)
1212
; strncpy -> __memset_chk, full overwrite
1313
define void @dse_strncpy_memset_chk_test1(ptr noalias %out, ptr noalias %in, i64 %n) {
1414
; CHECK-LABEL: @dse_strncpy_memset_chk_test1(
15-
; CHECK-NEXT: [[CALL:%.*]] = tail call ptr @strncpy(ptr [[OUT:%.*]], ptr [[IN:%.*]], i64 100)
16-
; CHECK-NEXT: [[CALL_2:%.*]] = tail call ptr @__memset_chk(ptr [[OUT]], i32 42, i64 100, i64 [[N:%.*]])
15+
; CHECK-NEXT: [[CALL_2:%.*]] = tail call ptr @__memset_chk(ptr [[OUT:%.*]], i32 42, i64 100, i64 [[N:%.*]])
1716
; CHECK-NEXT: ret void
1817
;
1918
%call = tail call ptr @strncpy(ptr %out, ptr %in, i64 100)
@@ -23,8 +22,7 @@ define void @dse_strncpy_memset_chk_test1(ptr noalias %out, ptr noalias %in, i64
2322

2423
define void @dse_memset_chk_eliminate_store1(ptr %out, i64 %n) {
2524
; CHECK-LABEL: @dse_memset_chk_eliminate_store1(
26-
; CHECK-NEXT: store i8 10, ptr [[OUT:%.*]], align 1
27-
; CHECK-NEXT: [[CALL_2:%.*]] = tail call ptr @__memset_chk(ptr [[OUT]], i32 42, i64 100, i64 [[N:%.*]])
25+
; CHECK-NEXT: [[CALL_2:%.*]] = tail call ptr @__memset_chk(ptr [[OUT:%.*]], i32 42, i64 100, i64 [[N:%.*]])
2826
; CHECK-NEXT: ret void
2927
;
3028
store i8 10, ptr %out
@@ -48,7 +46,6 @@ define void @dse_memset_chk_eliminate_store2(ptr %out, i64 %n) {
4846
define void @dse_memset_chk_eliminates_store_local_object_escapes_after(i64 %n) {
4947
; CHECK-LABEL: @dse_memset_chk_eliminates_store_local_object_escapes_after(
5048
; CHECK-NEXT: [[A:%.*]] = alloca [200 x i8], align 1
51-
; CHECK-NEXT: store i8 10, ptr [[A]], align 1
5249
; CHECK-NEXT: [[OUT_100:%.*]] = getelementptr i8, ptr [[A]], i64 100
5350
; CHECK-NEXT: store i8 10, ptr [[OUT_100]], align 1
5451
; CHECK-NEXT: [[CALL_2:%.*]] = tail call ptr @__memset_chk(ptr [[A]], i32 42, i64 100, i64 [[N:%.*]])
@@ -68,7 +65,6 @@ define void @dse_memset_chk_eliminates_store_local_object_escapes_before(i64 %n)
6865
; CHECK-LABEL: @dse_memset_chk_eliminates_store_local_object_escapes_before(
6966
; CHECK-NEXT: [[A:%.*]] = alloca [200 x i8], align 1
7067
; CHECK-NEXT: call void @use(ptr [[A]])
71-
; CHECK-NEXT: store i8 10, ptr [[A]], align 1
7268
; CHECK-NEXT: [[OUT_100:%.*]] = getelementptr i8, ptr [[A]], i64 100
7369
; CHECK-NEXT: store i8 0, ptr [[OUT_100]], align 1
7470
; CHECK-NEXT: [[CALL_2:%.*]] = tail call ptr @__memset_chk(ptr [[A]], i32 42, i64 100, i64 [[N:%.*]])

0 commit comments

Comments
 (0)