This is an archive of the discontinued LLVM Phabricator instance.

Avoid inline optimization for unwind_phase2 and unwind_phase2_forced
AbandonedPublic

Authored by xiongji90 on Oct 19 2022, 10:47 PM.

Details

Reviewers
MaskRay
compnerd
Group Reviewers
Restricted Project
Summary

Currently, when building libunwind with CET enabled, we will count the number of stack frames skipped in unwind process and adjust CET shadow stack based on this number. The logic is implemented in unwind_phase2 and unwind_phase2_forced functions and these 2 functions are called by _Unwind_RaiseException and _Unwind_ForcedUnwind.
However, when counting the number of stack frames skipped, current implementation assumes "unwind_phase2" and "unwind_phase2_forced" are not inline optimized, otherwise the number of stack frames must be changed. The assumption may be incorrect when compiler inlines these 2 functions, this patch adds "attribute((noinline))" for unwind_phase2 and unwind_phase2.

Diff Detail

Event Timeline

xiongji90 created this revision.Oct 19 2022, 10:47 PM
Herald added a reviewer: Restricted Project. · View Herald TranscriptOct 19 2022, 10:47 PM
Herald added a project: Restricted Project. · View Herald Transcript
xiongji90 requested review of this revision.Oct 19 2022, 10:47 PM
Herald added a project: Restricted Project. · View Herald TranscriptOct 19 2022, 10:47 PM

Hi, @MaskRay and @compnerd
Could you help review this patch?
Thanks very much.

Can you add the stacktrace to the description?

Can you add the stacktrace to the description?

Hi, @MaskRay
Following is stack trace which current implementation assumes:
---------------------------|
unwind_phase2
---------------------------|
_Unwind_RaiseException
---------------------------|
__cxa_throw
--------------------------|
user function frames...
--------------------------|

In unwind_phase2, we will go through stacks and count the number of stack frames which needs to be skipped. We initialize variable "framesWalked" to 1 in "unwind_phase2" and "unwind_phase2_forced", this is because these 2 functions have corresponding stack frame and also have corresponding records in CET shadow stack, so we need to remove CET shadow record for "unwind_phase2" and "unwind_phase2_forced" when unwinding normal stack. However, if "unwind_phase2" or "unwind_phase2_forced" are inlined, then there will be no corresponding stack frame and corresponding CET shadow stack record, the stack trace will turn to:

---------------------------|
_Unwind_RaiseException
---------------------------|
__cxa_throw
--------------------------|
user function frames...
--------------------------|

Under such circumstance, we need to initialize "framesWalked" to 0. Although current implementation does work, we can't control whether compiler will optimize unwind_phase2 away in the future, so suggest to add "noinline" to guard.

Thanks very much.

xiongji90 abandoned this revision.Nov 10 2022, 10:21 PM