Add an -fsanitize-trap-function flag that acts as -ftrap-function does, except only for traps generated by -fsanitize-trap.
Details
- Reviewers
samsonov
Diff Detail
Event Timeline
tools/clang/lib/CodeGen/CodeGenFunction.h | ||
---|---|---|
2889 ↗ | (On Diff #32649) | FIXME: Add doxygen comments |
Please upload the patch with more context (see http://llvm.org/docs/Phabricator.html).
tools/clang/include/clang/Driver/Options.td | ||
---|---|---|
610 ↗ | (On Diff #32649) | Fix the help text: Make trapping sanitizers issue a call to specified function rather than a trap instruction. |
tools/clang/include/clang/Frontend/CodeGenOptions.h | ||
205 ↗ | (On Diff #32649) | Fix the comment here as well. |
tools/clang/lib/CodeGen/CGExpr.cpp | ||
2388 ↗ | (On Diff #32649) | This is confusing. So, you have the following behavior whenever you need to emit a check for -fsanitize-trap=foo:
Do you really want it? Don't you need to skip (2) instead? If you do, you should carefully document it. |
2415 ↗ | (On Diff #32649) | This function should not be needed. |
2422 ↗ | (On Diff #32649) | Isn't it easier to just kill this function, and always pass in CGM.getCodeGenOpts().TrapFuncName where applicable? |
tools/clang/lib/CodeGen/CGExprScalar.cpp | ||
2386 ↗ | (On Diff #32649) | Why? Looks like this check is not emitted as a part of -fsanitize=signed-integer-overflow |
tools/clang/lib/Frontend/CompilerInvocation.cpp | ||
507 ↗ | (On Diff #32649) | Please parse this argument next to another sanitizer arguments. |
Can you please give a brief description of the motivation for this change? When would it be appropriate to use this rather than -ftrap-function?
Please also include an update for the Clang documentation to describe the new flag.
See https://llvm.org/bugs/show_bug.cgi?id=24443 (it's worth including this reference to change description).
tools/clang/lib/CodeGen/CGExpr.cpp | ||
---|---|---|
2388 ↗ | (On Diff #32649) | My interpretation of the current -ftrap-function help text ("Issue call to specified function rather than a trap instruction") is that if -ftrap-function is specified, clang should never emit a trap instruction if defined. Does this seem reasonable? I added a blurb to UsersManual.rst saying that it falls back to -ftrap-function if not specified. |
2422 ↗ | (On Diff #32649) | It's used in a few other places (__builtin_trap, __builtin_debugtrap, fall off the end of a function in -O0), so I think it's probably easier (and less error prone) to keep a copy of the function that fetches the TrapFuncName itself. |
I'd still like an answer to this. It's not clear to me what the purpose of this is, and why you'd want a custom runtime hook for sanitizer traps but not other traps. The only time we emit a trap using -ftrap-function where there is no corresponding sanitizer is for __builtin_trap(); is the intention that you still want a normal trap for that builtin?
The goal is to be able to give a useful fsanitize-specific error message ("fsanitize trap occurred"), while not lying and saying this for non-sanitize traps.
Looks good, thanks for working on this.
I added some code style comments.
lib/CodeGen/CGExpr.cpp | ||
---|---|---|
2398 | 80 columns | |
2408–2409 | 80 columns. | |
2420–2421 | 80 columns. | |
2424–2426 | Please run clang-format on lines you change. | |
lib/CodeGen/CodeGenFunction.h | ||
2891 | Don't add \brief if the comment is just one sentence (if you want to remove ones that were there previously, don't do it in the same commit, though). | |
2904 | Again, don't add \brief. | |
lib/Frontend/CompilerInvocation.cpp | ||
684 | clang-format here. |
lib/CodeGen/CGExpr.cpp | ||
---|---|---|
2303 | Yes |
My original intent was that users who wanted a different response to sanitizer failures would provide an alternative runtime library (defining the __ubsan_handle_* functions to do whatever they wanted). The trap mechanism was added for users who didn't want the code size increase of generating the calls to a handler function. I worry that we're piling on more and more ways of responding to ubsan failures with no underlying principled design.
Without this patch, you have (at least) two options:
- Use -fsanitize-trap and -ftrap-function=. You'll get calls on sanitizer failures, and also on explicit calls to __builtin_trap(). If we added a sanitizer for reaching __builtin_trap() -- which doesn't seem completely unreasonable -- these would all be sanitizer failures :)
- Use your own ubsan runtime library. There are about 20 functions you'd need to define, but you can define them all to be aliases of the same handler function. See ubsan_handlers.h in compiler-rt for a list of the symbols you need to provide.
Given the above, do you think your patch adds enough value to be worth our time to maintain?
With #1, it seems unfortunate to not be able to distinguish between a sanitize inserted __builtin_trap and code manually calling it. (Would there be an -fsanitize-trap=trap? :-)
With #2, we're worried about the generated code being noticeably worse in the unexceptional case than running without the sanitizers.
Compiling the following snippet with -O3 -fsanitize=unsigned-integer-overflow -fomit-frame-pointer and additional arguments generates:
unsigned foo(unsigned a, unsigned b, unsigned c, unsigned d) { return a + b + c + d; }
no additional arguments
foo: push {r4, r5, r6, r7, r8, lr} mov r5, r2 mov r2, r1 mov r1, r0 mov r0, #1 mov r8, r3 mov r4, #1 add r6, r1, r2 cmp r6, r1 movhs r0, #0 cmp r0, #0 bne .LBB0_4 .LBB0_1: add r7, r6, r5 cmp r7, r6 movhs r4, #0 cmp r4, #0 bne .LBB0_5 .LBB0_2: add r5, r7, r8 mov r0, #1 cmp r5, r7 movhs r0, #0 cmp r0, #0 bne .LBB0_6 .LBB0_3: mov r0, r5 pop {r4, r5, r6, r7, r8, lr} bx lr .LBB0_4: <overflow handling>
-fsanitize-trap=unsigned-integer-overflow
foo: add r1, r0, r1 mov r12, #1 cmp r1, r0 mov r0, #1 movhs r0, #0 cmp r0, #0 bne .LBB0_3 @ BB#1: add r2, r1, r2 cmp r2, r1 movhs r12, #0 cmp r12, #0 bne .LBB0_3 @ BB#2: add r0, r2, r3 mov r1, #1 cmp r0, r2 movhs r1, #0 cmp r1, #0 bxeq lr .LBB0_3: .long 3892305662 @ trap
-fsanitize-trap=unsigned-integer-overflow -fsanitize-trap-function=sanitize_trap
foo: push {r11, lr} ; Not quite perfect, but still better add r1, r0, r1 mov r12, #1 cmp r1, r0 mov r0, #1 movhs r0, #0 cmp r0, #0 bne .LBB0_3 @ BB#1: add r2, r1, r2 cmp r2, r1 movhs r12, #0 cmp r12, #0 bne .LBB0_3 @ BB#2: add r0, r2, r3 mov r1, #1 cmp r0, r2 movhs r1, #0 cmp r1, #0 popeq {r11, lr} bxeq lr .LBB0_3: bl sanitize_trap(PLT)
for sanitizer checks configured to trap.