Skip to content

Better runtime failure messages (not yet enabled by default) #25978

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Jul 12, 2019

Conversation

eeckstein
Copy link
Contributor

@eeckstein eeckstein commented Jul 5, 2019

Meaning:

  • Make runtime failure messages visible in release mode, which were previously only available in debug builds
  • Add messages for runtime failures, which didn't have a message at all, like arithmetic overflow.

All this is done via debug info, so there is no overhead in code generation. Thanks @adrian-prantl for the idea of implementing this with inline functions in the debug info.
When having debug info available, e.g. when running in the debugger, the failure message is displayed as inline function.

Examples:

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
    frame #0: 0x0000000100000c9c a.out`testit1(_:) [inlined] arithmetic overflow at test.swift:4:12 [opt]
   1   	
   2   	@inline(never)
   3   	func testit1(_ a: Int8) -> Int8 {
-> 4   	  return a + 1
   5   	}
   6   	
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
    frame #0: 0x0000000100000cbf a.out`testit3(_:) [inlined] Unexpectedly found nil while unwrapping an Optional value at test.swift:14:11 [opt]
   11
   12  	@inline(never)
   13  	func testit(_ a: Int?) -> Int {
-> 14  	  return a!
   15  	}
   16

This change is currently not enabled by default, but can be enabled with the option "-Xllvm -enable-trap-debug-info". Enabling this feature needs some changes in lldb. When the lldb part is done, this option can be removed and the feature enabled by default.

rdar://problem/51278690

@eeckstein eeckstein changed the title [do not merge] Better runtime failure messages Better runtime failure messages Jul 8, 2019
@eeckstein
Copy link
Contributor Author

@swift-ci test

@swift-ci
Copy link
Contributor

swift-ci commented Jul 8, 2019

Build failed
Swift Test Linux Platform
Git Sha - 79f89a2137345b45a1e02bdf313b90cc89ea1cb6

@swift-ci
Copy link
Contributor

swift-ci commented Jul 8, 2019

Build failed
Swift Test OS X Platform
Git Sha - 79f89a2137345b45a1e02bdf313b90cc89ea1cb6

@eeckstein
Copy link
Contributor Author

@swift-ci test

1 similar comment
@eeckstein
Copy link
Contributor Author

@swift-ci test

@swift-ci
Copy link
Contributor

swift-ci commented Jul 9, 2019

Build failed
Swift Test Linux Platform
Git Sha - edf78542909ddc4921c4d39725b591a217eb2ee9

@swift-ci
Copy link
Contributor

swift-ci commented Jul 9, 2019

Build failed
Swift Test OS X Platform
Git Sha - edf78542909ddc4921c4d39725b591a217eb2ee9

The SIL generation for this builtin also changes: instead of generating the cond_fail instructions upfront, let the optimizer generate it, if the operand is a static string literal.
In worst case, if the second operand is not a static string literal, the Builtin.condfail is lowered at the end of the optimization pipeline with a default message: "unknown program error".
To display a failure message in the debugger, create a function in the debug info which has the name of the failure message.
The debug location of the trap/cond_fail is then wrapped into this function and the function is declared as "inlined".
In case the debugger stops at the trap instruction, it displays the inline function, which looks like the failure message.
For example:

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0)
    frame #0: 0x0000000100000cbf a.out`testit3(_:) [inlined] Unexpectedly found nil while unwrapping an Optional value at test.swift:14:11 [opt]
   11
   12   @inline(never)
   13   func testit(_ a: Int?) -> Int {
-> 14     return a!
   15   }
   16

This change is currently not enabled by default, but can be enabled with the option "-Xllvm -enable-trap-debug-info".
Enabling this feature needs some changes in lldb. When the lldb part is done, this option can be removed and the feature enabled by default.
For using the improved condfail messages in the stdlib, we need a function, like precondition(), just taking a StaticString instead of a String for the message.
The existing (underscored) _precondition is a perfect fit for this, except that it's not printing the location info in debug builds.
This change makes _precondition() equivalent to precondition, just taking a StaticString as argument.

The other alternative would be to add another variant of precondition, just taking a StaticString. But we already have so many failure functions in Assert.swift, so adapting an existing one seems to be a better solution.
This effectively undos a change from 5 years ago which intentionally removed the location info from _precondition (rdar://problem/16958193).  But this was at a time where swift was not open source yet. So I think today it's okay to always add location information, even if it's from inside the stdlib. It can be even very useful for expert users for looking up the location the stdlib source.
…nil while unwrapping an optional" failure message.

Advantage: the failure message is now also visible in release builds.
@eeckstein eeckstein changed the title Better runtime failure messages Better runtime failure messages (not yet enabled by default) Jul 12, 2019
@eeckstein
Copy link
Contributor Author

@swift-ci test

@swift-ci
Copy link
Contributor

Build failed
Swift Test Linux Platform
Git Sha - edf78542909ddc4921c4d39725b591a217eb2ee9

@swift-ci
Copy link
Contributor

Build failed
Swift Test OS X Platform
Git Sha - edf78542909ddc4921c4d39725b591a217eb2ee9

@beccadax
Copy link
Contributor

@eeckstein We've reverted this because we think it may have broken four tests:

  • SILOptimizer/pound_assert.swift
  • SILOptimizer/existential_transform.swift
  • IRGen/condfail_message.swift
  • DebugInfo/linetable-codeview.swift

See e.g. https://ci.swift.org/job/oss-swift_tools-RA_stdlib-DA_test-simulator/715 for examples of the failures.

eeckstein added a commit to eeckstein/swift that referenced this pull request Feb 18, 2020
The implementation was done quite a while ago.
Now, that we have support in lldb (swiftlang/llvm-project#773), we can enable it by default in the compiler.

LLDB now shows the runtime failure reason, for example:

* thread #1, queue = 'com.apple.main-thread', stop reason = Swift runtime failure: arithmetic overflow
    frame #1: 0x0000000100000f0d a.out`testit(a=127) at trap_message.swift:4
   1
   2   	@inline(never)
   3   	func testit(_ a: Int8) -> Int8 {
-> 4   	  return a + 1
   5   	}
   6

For details, see swiftlang#25978

rdar://problem/51278690
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants