Skip to content

Conversation

@delcypher
Copy link

This patch implements an instrumentation plugin for the
-fbounds-safety soft trap mode first implemented in
#11645 (rdar://158088757).

The current implementation of -fbounds-safety traps works by emitting
calls to runtime functions intended to log the occurrence of a soft trap.
While the user could just set a breakpoint of these functions the
instrumentation plugin sets it automatically and provides several
additional features:

When debug info is available:

  • It adjusts the stop reason to be the reason for trapping. This is
    extracted from the artificial frame in the debug info (similar to
    -fbounds-safety hard traps).
  • It adjusts the selected frame to be the frame where the soft trap
    occurred.

When debug info is not available:

  • For the call-with-str soft trap mode the soft trap reason is
    read from the first argument register.
  • For the call-minimal soft trap mode the stop reason is adjusted
    to note its a bounds check failure but does not give further
    information because none is available.
  • In this situation the selected frame is not adjusted because in
    this mode the user will be looking at assembly and adjusting the
    frame makes things confusing.

This patch includes shell and api tests. The shell tests seemed like the
best way to test behavior when debug info is missing because those tests
make it easy to disable building with debug info completely.

rdar://163230807

@delcypher delcypher self-assigned this Nov 14, 2025
@delcypher delcypher added the clang:bounds-safety Issue relating to the experimental -fbounds-safety feature in Clang label Nov 14, 2025
@delcypher delcypher force-pushed the dliew/rdar-163230807-wip branch from f7206d3 to a15e413 Compare November 15, 2025 00:22
@delcypher
Copy link
Author

@swift-ci test

@delcypher
Copy link
Author

@swift-ci test llvm

@delcypher delcypher force-pushed the dliew/rdar-163230807-wip branch from a15e413 to c8af09b Compare November 15, 2025 02:09
@delcypher
Copy link
Author

@swift-ci test

@delcypher
Copy link
Author

@swift-ci test llvm

@delcypher
Copy link
Author

delcypher commented Nov 16, 2025

Windows failure looks completely unrelated to this PR:

21:30:12  C:\Program Files\CMake\bin\cmake.exe -B T:\x86_64-unknown-windows-msvc\DocC -S C:\Users\swift-ci\jenkins\workspace\apple-llvm-project-pull-request-windows\swift-docc -G Ninja -D ArgumentParser_DIR=T:/x86_64-unknown-windows-msvc/ArgumentParser/cmake/modules -D BUILD_SHARED_LIBS=YES -D CMAKE_BUILD_TYPE=Release -D CMAKE_C_COMPILER=T:/5/bin/clang-cl.exe -D CMAKE_C_COMPILER_TARGET=x86_64-unknown-windows-msvc -D CMAKE_C_FLAGS=/GS- /Gw /Gy /Oy /Oi /Zc:inline -D CMAKE_EXE_LINKER_FLAGS=/INCREMENTAL:NO /OPT:REF /OPT:ICF -D CMAKE_FIND_PACKAGE_PREFER_CONFIG=YES -D CMAKE_INSTALL_PREFIX=T:/Program Files/Swift/Toolchains/0.0.0+Asserts/usr -D CMAKE_MAKE_PROGRAM=C:/Program Files/Microsoft Visual Studio/2022/Community/Common7/IDE/CommonExtensions/Microsoft/CMake/Ninja/ninja.exe -D CMAKE_SHARED_LINKER_FLAGS=/INCREMENTAL:NO /OPT:REF /OPT:ICF -D CMAKE_STATIC_LIBRARY_PREFIX_Swift=lib -D CMAKE_Swift_COMPILER=T:/5/bin/swiftc.exe -D CMAKE_Swift_COMPILER_TARGET=x86_64-unknown-windows-msvc -D CMAKE_Swift_COMPILER_WORKS=YES -D CMAKE_Swift_FLAGS=-sdk \"T:/Program Files/Swift/Platforms/Windows.platform/Developer/SDKs/Windows.sdk\" -gnone -Xlinker /INCREMENTAL:NO -Xlinker /OPT:REF -Xlinker /OPT:ICF -D CMAKE_Swift_FLAGS_RELEASE=-O -D CMAKE_Swift_FLAGS_RELWITHDEBINFO=-O -D cmark-gfm_DIR=T:/Program Files/Swift/Toolchains/0.0.0+Asserts/usr/lib/cmake -D LMDB_DIR=T:/x86_64-unknown-windows-msvc/LMDB/cmake/modules -D SwiftASN1_DIR=T:/x86_64-unknown-windows-msvc/ASN1/cmake/modules -D SwiftCrypto_DIR=T:/x86_64-unknown-windows-msvc/Crypto/cmake/modules -D SwiftMarkdown_DIR=T:/x86_64-unknown-windows-msvc/Markdown/cmake/modules -D SymbolKit_DIR=T:/x86_64-unknown-windows-msvc/SymbolKit/cmake/modules
21:30:12  -- The C compiler identification is Clang 21.1.6 with MSVC-like command-line
21:30:12  -- The Swift compiler identification is Apple 6.3
21:30:13  -- Detecting C compiler ABI info
21:30:13  -- Detecting C compiler ABI info - done
21:30:13  -- Check for working C compiler: T:/5/bin/clang-cl.exe - skipped
21:30:13  -- Detecting C compile features
21:30:13  -- Detecting C compile features - done
21:30:13  CMake Error at Sources/CMakeLists.txt:11 (add_subdirectory):
21:30:13    The source directory
21:30:13  
21:30:13      C:/Users/swift-ci/jenkins/workspace/apple-llvm-project-pull-request-windows/swift-docc/Sources/SwiftDocCUtilities
21:30:13  
21:30:13    does not contain a CMakeLists.txt file.
21:30:13  
21:30:13  
21:30:13  -- Configuring incomplete, errors occurred!
21:30:13  Error: Error: cmake.exe exited with code 1.

likely caused by swiftlang/swift-docc#1331. Looks like swiftlang/swift-docc#1352 is out to revert this change.

@delcypher
Copy link
Author

@swift-ci please test windows platform

delcypher added a commit to delcypher/apple-llvm-project that referenced this pull request Nov 18, 2025
This patch adds `LLDBLog::InstrumentationRuntime` as a log channel to
provide an appropriate channel for instrumentation runtime plugins as
previously one did not exist.

A small use of the channel is added to illustrate its use. The logging
added is not intended to be comprehensive.

This is primarily motivated by an `-fbounds-safety` instrumentation
plugin (swiftlang#11835).

rdar://164920875
delcypher added a commit to delcypher/apple-llvm-project that referenced this pull request Nov 18, 2025
This patch adds `LLDBLog::InstrumentationRuntime` as a log channel to
provide an appropriate channel for instrumentation runtime plugins as
previously one did not exist.

A small use of the channel is added to illustrate its use. The logging
added is not intended to be comprehensive.

This is primarily motivated by an `-fbounds-safety` instrumentation
plugin (swiftlang#11835).

rdar://164920875
delcypher added a commit to delcypher/apple-llvm-project that referenced this pull request Nov 18, 2025
This patch adds `LLDBLog::InstrumentationRuntime` as a log channel to
provide an appropriate channel for instrumentation runtime plugins as
previously one did not exist.

A small use of the channel is added to illustrate its use. The logging
added is not intended to be comprehensive.

This is primarily motivated by an `-fbounds-safety` instrumentation
plugin (swiftlang#11835).

rdar://164920875
delcypher added a commit to llvm/llvm-project that referenced this pull request Nov 18, 2025
This patch adds `LLDBLog::InstrumentationRuntime` as a log channel to
provide an appropriate channel for instrumentation runtime plugins as
previously one did not exist.

A small use of the channel is added to illustrate its use. The logging
added is not intended to be comprehensive.

This is primarily motivated by an `-fbounds-safety` instrumentation
plugin (swiftlang#11835).

rdar://164920875
This patch adds `LLDBLog::InstrumentationRuntime` as a log channel to
provide an appropriate channel for instrumentation runtime plugins as
previously one did not exist.

A small use of the channel is added to illustrate its use. The logging
added is not intended to be comprehensive.

This is primarily motivated by an `-fbounds-safety` instrumentation
plugin (swiftlang#11835).

rdar://164920875
(cherry picked from commit 46565f3)
This refactors the soft trap runtime test so the soft trap runtime
implementation exists in its own file. This has several advantages:

* It let's the runtime be built without debug info which will be the
  common case uses hit
* It prevents the risk of infinite recursion because it isn't safe
  to build the soft trap runtime with -fbounds-safety soft trap mode
  enabled.
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Nov 18, 2025
…(#168508)

This patch adds `LLDBLog::InstrumentationRuntime` as a log channel to
provide an appropriate channel for instrumentation runtime plugins as
previously one did not exist.

A small use of the channel is added to illustrate its use. The logging
added is not intended to be comprehensive.

This is primarily motivated by an `-fbounds-safety` instrumentation
plugin (swiftlang/llvm-project#11835).

rdar://164920875
@delcypher delcypher force-pushed the dliew/rdar-163230807-wip branch from 3c3ccb0 to d191072 Compare November 18, 2025 19:34
@delcypher delcypher requested a review from a team as a code owner November 18, 2025 19:34
@delcypher delcypher changed the base branch from stable/21.x to swift/release/6.3 November 18, 2025 19:34
@delcypher
Copy link
Author

Changing target from stable/21.x to swift/release/6.3.

@delcypher
Copy link
Author

@swift-ci test

@delcypher
Copy link
Author

@jimingham @Michael137 This is ready for another round of reviews.

@jimingham
Copy link

There's one obsolete TODO about adding an Instrumentation Log Channel which you in fact already did. You probably do want to log the breakpoint having no locations around where the TODO is.

Other than that, LGTM.

Copy link

@Michael137 Michael137 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apart from some nits this LGTM also

High-level question though. Why couldn't the existing verbose-trap frame recognizer be made to understand the soft trap frame? Couldn't we have just added it to the recognized regex and then re-used the existing frame recognizer to display the stop reason etc.? Is it the no-debug-info cases that are special and need the separate plugin? Makes me wonder if we could still re-use the verbose trap recognizer for the debug-info case. But might be easier said than done/might missing something completely

@delcypher
Copy link
Author

@Michael137

High-level question though. Why couldn't the existing verbose-trap frame recognizer be made to understand the soft trap frame? Couldn't we have just added it to the recognized regex and then re-used the existing frame recognizer to display the stop reason etc.? Is it the no-debug-info cases that are special and need the separate plugin? Makes me wonder if we could still re-use the verbose trap recognizer for the debug-info case. But might be easier said than done/might missing something completely

Good question. Technically we could extend the verbose-trap frame recognizer too but something this plugin does that the verbose trap frame recognizer doesn't do is set a breakpoint. With this plugin we automatically stop on a soft trap which is the behavior I wanted.

@Michael137
Copy link

@Michael137

High-level question though. Why couldn't the existing verbose-trap frame recognizer be made to understand the soft trap frame? Couldn't we have just added it to the recognized regex and then re-used the existing frame recognizer to display the stop reason etc.? Is it the no-debug-info cases that are special and need the separate plugin? Makes me wonder if we could still re-use the verbose trap recognizer for the debug-info case. But might be easier said than done/might missing something completely

Good question. Technically we could extend the verbose-trap frame recognizer too but something this plugin does that the verbose trap frame recognizer doesn't do is set a breakpoint. With this plugin we automatically stop on a soft trap which is the behavior I wanted.

Oh i see, yea we would need to stop from the frame recognizer to trigger. Technically we could make it stop at the parent frame, and then the frame recognizer kicks in? And that could be responsible for showing the stop reason? Then the frame recognizer benefits from working in the no-debug-info case too. But i'm not 100% whether this Just Works. Might be worth a try. Or if you prefer, we can merge this and then simplify/merge with the frame recognizer as a follow-up.

@delcypher
Copy link
Author

delcypher commented Nov 19, 2025

Oh i see, yea we would need to stop from the frame recognizer to trigger. Technically we could make it stop at the parent frame, and then the frame recognizer kicks in? And that could be responsible for showing the stop reason?

The logic for getting the stop reason for -fbounds-safety soft traps is a bit complicated here. This plugin recognizes two situations:

  1. Call to one of the soft trap functions where debug info is available in the caller. In this case we use the artificial stackframe in the debug info to get the stop reason (just like the verbose trap recognizer does).

  2. Call to one of the soft trap functions where debug info is not available in the caller. In this case we inspect register state (only for one of the soft trap functions) to try to get the stop reason. This is something that the verbose frame recognizer doesn't do currently.

Pulling all that logic into the existing verbose stackframe recognizer doesn't make sense to me because __builtin_verbose_trap() doesn't emit code+debug info like this. It would also really over complicate the implementation just for this use case. If we did decide to move the logic into a stackframe recognizer I'd argue it probably should be its own separate one.

Given that instrumentation plugins supports the exact thing I need (set a breakpoint and when its hit do some analysis and set the stop reason) I think it's cleaner to keep this PR as is. The common logic for getting the trap reason from the debug info has already been refactored so that both this PR and the verbose stackframe recognizer can use it so there's no unnecessary duplication of code.

Then the frame recognizer benefits from working in the no-debug-info case too.

The only use case I see for that is if the plugin was deliberately switched off and then a breakpoint is set manually. Currently the stop reason won't be set to the trap reason. I'm not sure if that's desirable or not. If we change the stop reason it's less clear that the user's breakpoint was hit, OTOH it's harder to see the trap reason. I doubt this is a common use case because the user would need to known that the plugin exists, and how to turn it off.

But i'm not 100% whether this Just Works. Might be worth a try. Or if you prefer, we can merge this and then simplify/merge with the frame recognizer as a follow-up.

I would prefer to just merge. I've file a radar (rdar://165066642) about considering moving some of the logic into a stackframe recognizer.

…fety soft traps

This patch implements an instrumentation plugin for the
`-fbounds-safety` soft trap mode first implemented in
swiftlang#11645 (rdar://158088757).

The current implementation of -fbounds-safety traps works by emitting
calls to runtime functions intended to log the occurrence of a soft trap.
While the user could just set a breakpoint of these functions the
instrumentation plugin sets it automatically and provides several
additional features:

When debug info is available:

* It adjusts the stop reason to be the reason for trapping. This is
  extracted from the artificial frame in the debug info (similar to
  -fbounds-safety hard traps).
* It adjusts the selected frame to be the frame where the soft trap
  occurred.

When debug info is not available:

* For the `call-with-str` soft trap mode the soft trap reason is
  read from the first argument register.
* For the `call-minimal` soft trap mode the stop reason is adjusted
  to note its a bounds check failure but does not give further
  information because none is available.
* In this situation the selected frame is not adjusted because in
  this mode the user will be looking at assembly and adjusting the
  frame makes things confusing.

This patch includes shell and api tests. The shell tests seemed like the
best way to test behavior when debug info is missing because those tests
make it easy to disable building with debug info completely.

rdar://163230807
@delcypher delcypher force-pushed the dliew/rdar-163230807-wip branch from a1e85fe to 795052d Compare November 19, 2025 19:52
@delcypher
Copy link
Author

@swift-ci test

@delcypher
Copy link
Author

I've squash the feedback commits into the relevant commit and I've kicked off PR testing.

@Michael137
Copy link

  1. Call to one of the soft trap functions where debug info is not available in the caller. In this case we inspect register state (only for one of the soft trap functions) to try to get the stop reason. This is something that the verbose frame recognizer doesn't do currently.

Pulling all that logic into the existing verbose stackframe recognizer doesn't make sense to me because __builtin_verbose_trap() doesn't emit code+debug info like this. It would also really over complicate the implementation just for this use case. If we did decide to move the logic into a stackframe recognizer I'd argue it probably should be its own separate one.

Ok that makes sense. I naively thought we'd be able to share the logic which recognizes the stop reason in the no-debug-info case. But sounds like for verbose_trap that would have to look very different to the soft trap case.

I would prefer to just merge. I'll file a radar about considering moving some of the logic into a stackframe recognizer.

Sounds good to me!

@delcypher
Copy link
Author

@swift-ci test windows platform

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:bounds-safety Issue relating to the experimental -fbounds-safety feature in Clang

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants