This is an archive of the discontinued LLVM Phabricator instance.

Add a no_sanitize_vptr function attribute.
Needs ReviewPublic

Authored by ochang on Apr 16 2015, 1:52 PM.

Details

Reviewers
samsonov
rsmith

Diff Detail

Event Timeline

ochang updated this revision to Diff 23879.Apr 16 2015, 1:52 PM
ochang retitled this revision from to Add a no_sanitize_vptr function attribute..
ochang updated this object.
ochang edited the test plan for this revision. (Show Details)
ochang added a subscriber: inferno.
ochang added a subscriber: Unknown Object (MLST).Apr 16 2015, 1:56 PM
ochang updated this revision to Diff 23880.Apr 16 2015, 1:57 PM

fix comment

ochang updated this revision to Diff 23885.Apr 16 2015, 3:48 PM

Move check

ochang updated this revision to Diff 23886.Apr 16 2015, 3:49 PM

Fix comment

rsmith edited edge metadata.Apr 16 2015, 4:26 PM

I'm not convinced that adding one attribute per sanitizer is the right design here -- it doesn't seem to scale very well. Have you considered an attribute like

__attribute__((no_sanitize("list,of,sanitizers"))) void fn() { ... }

where the list is parsed as if it were specified as -fno-sanitize=list,of,sanitizers on the command line?

include/clang/Basic/Attr.td
1406

UBSan is not usually capitalized this way.

include/clang/Basic/AttrDocs.td
965

Grammar error around "for should".

Quuxplusone added inline comments.
test/CodeGen/no-sanitize-vtpr.cpp
1 ↗(On Diff #23886)

Typo in the name of this test: vtpr should be vptr.

17 ↗(On Diff #23886)

If I understand the feature correctly, the idea is that UBSan inserts runtime checks for various undefined behaviors, including the undefined behavior of down-casting Bar* to Foo* in the case that the original Bar* doesn't actually point to an instance of Foo.

However, this particular test case is statically detectable as undefined behavior, isn't it? and then on top of that, the assignment is dead and shouldn't really be generating any code at all. I don't think a proper implementation of UBSan would insert any runtime check here (and if the current implementation *does* insert a check here, it's not a proper implementation yet).

A real test case would be something like

Foo *testfunc1(Bar *bar) {
  // CHECK: testfunc1
  // CHECK: call void @__ubsan_handle_dynamic_type_cache_miss
  return static_cast<Foo*>(bar); // down-casting
}
__attribute__((no_sanitize_vptr)) Foo *testfunc2(Bar *bar) {
  // CHECK: testfunc2
  // CHECK-NOT: call void @__ubsan_handle_dynamic_type_cache_miss
  return static_cast<Foo*>(bar); // down-casting
}
ochang updated this revision to Diff 23942.Apr 17 2015, 10:00 AM
ochang edited edge metadata.

address some comments

I'm not convinced that adding one attribute per sanitizer is the right design here -- it doesn't seem to scale very well. Have you considered an attribute like

__attribute__((no_sanitize("list,of,sanitizers"))) void fn() { ... }

where the list is parsed as if it were specified as -fno-sanitize=list,of,sanitizers on the command line?

This does seem like a much better way of doing this. Should I change this in this patch?

What does everyone else think?

include/clang/Basic/Attr.td
1406

Fixed

include/clang/Basic/AttrDocs.td
965

Fixed.

test/CodeGen/no-sanitize-vtpr.cpp
1 ↗(On Diff #23886)

Good catch, fixed.

17 ↗(On Diff #23886)

I based these tests off an existing test - ubsan-type-blacklist.cpp, which led me to assumed it was OK to assume that these checks will be inserted for those cases. Should I change that too?

I've replaced this with something similar to yours (with added CHECK: ret) since call void @__ubsan_handle_dynamic_type_cache_miss gets inserted somewhere after testfunc2 too.

samsonov edited edge metadata.Apr 20 2015, 4:38 PM

I'm not convinced that adding one attribute per sanitizer is the right design here -- it doesn't seem to scale very well. Have you considered an attribute like

__attribute__((no_sanitize("list,of,sanitizers"))) void fn() { ... }

where the list is parsed as if it were specified as -fno-sanitize=list,of,sanitizers on the command line?

This does seem like a much better way of doing this. Should I change this in this patch?

What does everyone else think?

I agree with this suggestion. It would be cool to have a single attribute like this, and later deprecate no_sanitize_address, no_sanitize_thread and no_sanitize_memory.

I'm not convinced that adding one attribute per sanitizer is the right design here -- it doesn't seem to scale very well. Have you considered an attribute like

__attribute__((no_sanitize("list,of,sanitizers"))) void fn() { ... }

where the list is parsed as if it were specified as -fno-sanitize=list,of,sanitizers on the command line?

This does seem like a much better way of doing this. Should I change this in this patch?

What does everyone else think?

I agree with this suggestion. It would be cool to have a single attribute like this, and later deprecate no_sanitize_address, no_sanitize_thread and no_sanitize_memory.

I can put together another patch in the next few days, unless someone else (more experienced) wants to take this?

samsonov added a subscriber: pcc.May 7 2015, 9:33 PM

+pcc who also encountered the requirement for this attribute in http://reviews.llvm.org/D6095