Skip to content

Incorrect stack coloring for alloca in SEH cleanuppad #66984

@nikic

Description

@nikic

Consider the following example (https://llvm.godbolt.org/z/h1WovoPMG):

@type_info = external global ptr

define void @test(ptr %arg) personality ptr @__CxxFrameHandler3 {
bb:
  %a1 = alloca ptr, align 4
  %a2 = alloca ptr, align 4
  call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %a2)
  invoke void @throw()
          to label %bb14 unwind label %bb8

bb8:                                              ; preds = %bb7
  %i9 = cleanuppad within none []
  call void @llvm.lifetime.start.p0(i64 4, ptr nonnull %a1)
  store ptr %arg, ptr %a1, align 4
  call fastcc void @foo(ptr %a1) [ "funclet"(token %i9) ]
  call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %a1)
  cleanupret from %i9 unwind label %bb15

bb14:                                             ; preds = %bb7
  unreachable

bb15:                                             ; preds = %bb13, %bb5
  %cs = catchswitch within none [label %bb17] unwind to caller

bb17:                                             ; preds = %bb15
  %cp = catchpad within %cs [ptr @type_info, i32 8, ptr %a2]
  %p = load ptr, ptr %a2, align 4
  call fastcc void @cleanup(ptr %p) [ "funclet"(token %cp) ]
  catchret from %cp to label %exit

exit:
  call void @llvm.lifetime.end.p0(i64 4, ptr nonnull %a2)
  ret void
}

declare i32 @__CxxFrameHandler3(...)
declare void @throw()
declare void @cleanup(ptr)
declare void @foo(ptr)
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture)
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture)

Here %a1 has a lifetime fully contained within the cleanuppad, while %a2 has a lifetime across the whole function. However, the first use of %a2 is inside the catchpad. %a2 here is the pointer into which the exception object for the catchpad gets written.

With stackcoloring-lifetime-start-on-first-use (the default), %a1 and %a2 are allocated to the same stack slot. On the surface, this looks fine (because %a2 is only used after the cleanuppad). However, there is a quirk of SEH exception handling that makes this incorrect: The exception will be copied into %a2 by the personality function before both the cleanuppad and catchpad are called. As such, the write to %a2 happens earlier than our IR modeling implies.

There has been a patch to fix this issue in https://reviews.llvm.org/D86673. Unfortunately, that patch does not handle this case, because it checks for NumLoadInCatchPad[slot] > 1 -- I think the intention might have been to write > 0. (Funnily, just completely undoing the changes from that patch doesn't make the patch test case fail...)

Metadata

Metadata

Assignees

Type

No type

Projects

Status

Done

Relationships

None yet

Development

No branches or pull requests

Issue actions