-
Notifications
You must be signed in to change notification settings - Fork 10.5k
New assertions support #73675
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
New assertions support #73675
Conversation
@swift-ci Please test |
Note that this is the first piece of this proposed change. I wanted to leave it this way initially to get feedback on the overall design.
|
Other notes:
|
<< "file " << f << ", " | ||
<< "line " << line << "." | ||
<< std::endl; | ||
abort(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be handy to have more options than (a) trap on first assertion failure (b) ignore all assertions, considering that discovering which assertions are incorrect will be a gradual process, and the first assertion that fails may not be related to the problem directly being solved.
For example:
- print assertions that fail (and backtraces) but keep running
- trap on the Nth assertion
- break on assertion failures but keep running (
LLVM_BUILTIN_DEBUGTRAP
) - break on the Nth assertion failure
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All of that could be handled with future changes to this function, if we made the function declaration to not be [[noreturn]]
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added two very basic controls as an experiment:
-Xllvm -assert-help Dumps a list of assertion control options the first time an assertion is hit
-Xllvm -assert-continue Assertion failures are printed but don't abort()
If this general approach (using -Xllvm) works for folks, then this seems pretty easy to expand with whatever other controls we might like. Another possibility would be to provide an interactive mode similar to what @al45tair did for backtracing: An assertion would then print a prompt and wait for you to press a key. You could choose to continue, drop into a debugger, or abort(). After a timeout, the default handling would proceed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Two sub-variants of the above could integrate better with complex builds: emit a warning on failure, and emit an error on failure (both continuing execution afterwards). But obviously does not have to be in the first version of this!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, I plan to keep the first version pretty basic: There's a lot of potentially-disruptive work to merge this, and I want to be sure folks are comfortable with me roto-tilling all the assertions in the project. Once that's done, there are many ways to improve how assertions actually get reported and processed at runtime.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might also be good to have a selective continue option, like:
-Xllvm -assert-work-around=TypeCheckAttr.cpp:181
This would provide a way to work around a specific assertion that's been investigated and found to be spurious for a particular project.
This adds three new assertion macros: * `ASSERT` - always compiled in, always checked * `CONDITIONAL_ASSERT` - always compiled in, checked whenever the `-compiler-assertions` flag is provided * `DEBUG_ASSERT` - only compiled into debug builds, always checked when compiled in (functionally the same as Standard C `assert`) The new `-compiler-assertions` flag is recognized by both `swift-frontend` and `swiftc`. The goal is to eventually replace every use of `assert` in the compiler with one of the above: * Most assertions will use `ASSERT` (most assertions should always be present and checked, even in release builds) * Expensive assertions can use `CONDITIONAL_ASSERT` to be suppressed by default * A few very expensive and/or brittle assertions can use `DEBUG_ASSERT` to be compiled out of release builds This should: * Improve quality by catching errors earlier, * Accelerate compiler triage and debugging by providing more accurate crash dumps by default, and * Allow compiler engineers and end users alike to add `-compiler-assertions` to get more accurate failure diagnostics with any compiler
ff03746
to
37e5f30
Compare
I wonder if we could make the assertion macros preserve register state. One of the problems we have, especially on Darwin where I have some ideas on this front; I'll ping you on Slack. |
This looks great! I'm excited to get this in. |
@swift-ci Please test |
2 weeks with no-one expressing concerns with the overall approach here -- just lots of good ideas about how to refine the assertion reporting and handling, all of which can be pursued incrementally with future changes. So I'll go ahead and land this and proceed with the next step (including the new header into basically everywhere). |
Oh yeah: @mikeash I'm still not sure how/if to use this in the runtime. My goal right now is the compiler proper. If you think this would be good in the runtime too, we should talk about how to make that work. (Will require dropping the assertion failure handler into the runtime lib and figuring out an appropriate way to control the assertion behavior.) |
I'd love to see this in the runtime too. |
Agreed. The only thing to watch out for is that there are some cases (demangling being one such) where it makes sense to assert always in the runtime, but it doesn't make sense when the code is being invoked from LLDB (we don't want the debugger to crash with an assertion failure — it often speculatively tries things, that being the nature of the beast). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry for the late review; didn't see this when it was new.
Bottom line: I like this idea! We've needed to rethink compiler assertions for a while now.
<< "file " << f << ", " | ||
<< "line " << line << "." | ||
<< std::endl; | ||
abort(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It might also be good to have a selective continue option, like:
-Xllvm -assert-work-around=TypeCheckAttr.cpp:181
This would provide a way to work around a specific assertion that's been investigated and found to be spurious for a particular project.
This adds three new assertion macros:
ASSERT
- always compiled in, always checkedCONDITIONAL_ASSERT
- always compiled in, checked whenever the-compiler-assertions
flag is providedDEBUG_ASSERT
- only compiled into debug builds, always checked when compiled in (functionally the same as Standard Cassert
)The new
-compiler-assertions
flag is recognized by bothswift-frontend
andswiftc
.The goal is to eventually replace every use of
assert
in the compiler with one of the above:ASSERT
(most assertions should always be present and checked, even in release builds)CONDITIONAL_ASSERT
to be suppressed by defaultDEBUG_ASSERT
to be compiled out of release builds(Of course, we have a lot of flaky assertions today, so in the near-term,
CONDITIONAL_ASSERT
will likely be used far more heavily than is really appropriate until we can work through those.)This should:
-compiler-assertions
to get more accurate failure diagnostics with any compiler