This is an archive of the discontinued LLVM Phabricator instance.

[sanitizer] Add -fsanitize-trap-function.
Needs ReviewPublic

Authored by jmgao on Aug 19 2015, 6:23 PM.

Details

Reviewers
samsonov
Summary
Add an -fsanitize-trap-function flag that acts as -ftrap-function
does, except only for traps generated by -fsanitize-trap.

Diff Detail

Event Timeline

jmgao updated this revision to Diff 32649.Aug 19 2015, 6:23 PM
jmgao retitled this revision from to [sanitizer] Add -fsanitize-trap-function..
jmgao updated this object.
jmgao added a reviewer: samsonov.
jmgao set the repository for this revision to rL LLVM.
jmgao added a subscriber: danalbert.
jmgao added inline comments.
tools/clang/lib/CodeGen/CodeGenFunction.h
2889 ↗(On Diff #32649)

FIXME: Add doxygen comments

samsonov edited subscribers, added: cfe-commits, rsmith; removed: llvm-commits.Aug 20 2015, 11:46 AM
samsonov edited edge metadata.Aug 20 2015, 12:02 PM

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:

  1. Emit a call to -fsanitize-trap-function, if it's specified
  2. Otherwise, emit a call to -ftrap-function, if it's specified
  3. Otherwise, emit a trap instruction.

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.

jmgao updated this revision to Diff 32736.Aug 20 2015, 1:40 PM
jmgao edited edge metadata.

Uploading diff with arcanist.

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).

jmgao marked 8 inline comments as done.Aug 20 2015, 2:50 PM
jmgao added inline comments.
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.

jmgao updated this revision to Diff 32755.Aug 20 2015, 2:56 PM
jmgao marked 2 inline comments as done.

Address comments

jmgao updated this revision to Diff 32756.Aug 20 2015, 2:59 PM

Improve comment

Overall, this looks reasonable to me, but I'd like Richard to confirm he's fine with this change as well.

docs/UsersManual.rst
1121

for sanitizer checks configured to trap.

include/clang/Driver/Options.td
610

80 cols

lib/CodeGen/CodeGenFunction.h
2895

You can probably make this private

2899

And this

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?

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?

jmgao added a comment.Aug 20 2015, 4:29 PM

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?

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.

jmgao updated this revision to Diff 32768.Aug 20 2015, 4:45 PM

Make option fit in 80 cols

jmgao updated this revision to Diff 32769.Aug 20 2015, 4:47 PM

Doc fix, 80 col

jmgao updated this revision to Diff 32776.Aug 20 2015, 5:19 PM
jmgao marked 2 inline comments as done.

Make methods private

filcab added a subscriber: filcab.Aug 20 2015, 5:42 PM

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).
I would probably remove the first comma, too.

2904

Again, don't add \brief.

lib/Frontend/CompilerInvocation.cpp
684

clang-format here.

jmgao updated this revision to Diff 32788.Aug 20 2015, 8:02 PM
jmgao marked 7 inline comments as done.

clang-format, remove \brief from modified doxygen comments.

It seems you missed some \brief. Other than that, no complaints on this side.

lib/CodeGen/CGExpr.cpp
2303

Did clang-format do this?

lib/CodeGen/CodeGenFunction.h
2900

There's still a \brief here.

2904

I still see \brief.

jmgao updated this revision to Diff 32833.Aug 21 2015, 9:29 AM

Remove more \briefs

jmgao marked an inline comment as done.Aug 21 2015, 9:34 AM
jmgao added inline comments.
lib/CodeGen/CGExpr.cpp
2303

Yes

jmgao marked 4 inline comments as done.Aug 21 2015, 9:35 AM
jmgao added a comment.Aug 27 2015, 3:03 PM

Ping, I think @samsonov was waiting on @rsmith's feedback on the following:

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?

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.

Ping, I think @samsonov was waiting on @rsmith's feedback on the following:

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.

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:

  1. 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 :)
  2. 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?

jmgao added a comment.Aug 27 2015, 6:53 PM

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)