This is an archive of the discontinued LLVM Phabricator instance.

Preemptively disable unsigned integer sanitization in 32 and 64 bit versions of __murmur2_or_cityhash
ClosedPublic

Authored by danielaustin on Jan 7 2016, 3:19 PM.

Details

Summary

When using ubsan on an x86 target, specifically when calling find on an unordered_map, unsigned integer overflow is detected and an abort occurs. More specifically, the following snippet illustrates the behavior:

#include <unordered_map>

std::unordered_map<std::string, uint32_t> lookup_table;
...
std::unordered_map<std::string, uint32_t>::const_iterator it = lookup_table.find(item);

The find call eventually calls down to __murmur2_or_cityhash, which contains the benign unsigned integer overflow. Disabling sanitization for this function prevents the abort from occurring.

Diff Detail

Repository
rL LLVM

Event Timeline

danielaustin retitled this revision from to Preemptively disable unsigned integer sanitization in 32 and 64 bit versions of __murmur2_or_cityhash.
danielaustin updated this object.
danielaustin set the repository for this revision to rL LLVM.
danielaustin added a subscriber: danielaustin.
mclow.lists edited edge metadata.Jan 8 2016, 11:18 AM

My first reaction to this patch is "this code is doing perfectly legal things. UBSAN should not be complaining about it."

My second thought is "if we have to do this, why can't we use C++ attributes instead of __attribute?"
What happens if you use GCC (since gcc 4.9 and later support UBSAN).

danalbert edited edge metadata.Jan 8 2016, 11:22 AM

My first reaction to this patch is "this code is doing perfectly legal things. UBSAN should not be complaining about it."

ubsan has a switch for flagging unsigned integer overflows too. While well defined, we've found that they can cause all kinds of security issues, so for a number of projects in Android we have enabled this check for mitigation purposes. This patch just tells the compiler that we know we're relying on the wrapping behavior here, and that it shouldn't abort in this case.

I had spoken with @EricWF about this yesterday and he said that it was something he'd been meaning to do for a while.

I would suggest a different direction:
In <__config> define a macro named something like _LIBCPP_DISABLE_ASAN_UNSINGNED_INTEGER_CHECK to be either empty or __attribute((no_sanitize("unsigned integer"))), and use that in <memory>.

That way:

  • A user can define it at build time
  • We can use different text for different compilers.

That seems reasonable to me. Steve, Dan, any forseeable issues there?

Details:

in the clang section of __config, add:

#ifndef _LIBCPP_DISABLE_ASAN_UNSINGNED_INTEGER_CHECK
#define _LIBCPP_DISABLE_ASAN_UNSINGNED_INTEGER_CHECK __attribute((no_sanitize("unsigned integer")))
#endif

at the end of __config add:

#ifndef _LIBCPP_DISABLE_ASAN_UNSINGNED_INTEGER_CHECK
#define _LIBCPP_DISABLE_ASAN_UNSINGNED_INTEGER_CHECK
#endif

and then use _LIBCPP_DISABLE_ASAN_UNSINGNED_INTEGER_CHECK in <memory>.

If that's agreeable, I can just make that change.
If @danielaustin wants to prepare a new patch, we can review that.

Maybe spelling it _LIBCPP_DISABLE_ASAN_UNSIGNED_INTEGER_CHECK instead of _LIBCPP_DISABLE_ASAN_UNSINGNED_INTEGER_CHECK would be a better idea.

I'm good with that. Probably should be called
_LIBCPP_DISABLE_UBSAN_UNSIGNED_INTEGER_CHECK but otherwise I see no
problems

Nit: it's a UBSAN check, not an ASAN check

@danielaustin - Have you built libc++ with your proposed change? I'm getting compile errors building the dylib.

The original change, yes. Can I see your issues?

Here you go:

In file included from /Sources/LLVM/llvm/projects/libcxx/src/condition_variable.cpp:14:
In file included from /Sources/LLVM/llvm/projects/libcxx/include/condition_variable:112:
/Sources/LLVM/llvm/projects/libcxx/include/memory:3198:1: error: expected unqualified-id
template <class _Size>
^
/Sources/LLVM/llvm/projects/libcxx/include/memory:3351:1: error: expected unqualified-id
template <class _Size>
^
In file included from /Sources/LLVM/llvm/projects/libcxx/src/mutex.cpp:11:
In file included from /Sources/LLVM/llvm/projects/libcxx/include/mutex:177:
In file included from /Sources/LLVM/llvm/projects/libcxx/include/functional:477:
/Sources/LLVM/llvm/projects/libcxx/include/memory:3198:1: error: expected unqualified-id
template <class _Size>
^
/Sources/LLVM/llvm/projects/libcxx/include/memory:3351:1: error: expected unqualified-id
template <class _Size>
^
2 errors generated.

if I move the __attribute after the template <class _Size> it works better; but warns about "unknown attribute" instead.

I got these in the android build as well, but not on llvm ToT (weird...) If
the __attribute line was unconditional (no ifdef's) and on the same line as
the function it was applied to, it compiled and worked as expected.

Just resync'ed will try again on llvm and see what I get

Ah, yes. clang is not the default on my workstation (used to build configs
setting custom clang path for me). It builds fine with gcc, but I see
exactly what you are seeing with clang.

I'll wait for you to update your patch, then.

danielaustin edited edge metadata.

Refactored as Marshall suggested. Successfully compiled with clang & gcc.

Other than the placement of the macro in memory, this looks good to me.

include/memory
3197 ↗(On Diff #44526)

That's not where I would have expected it to go - I would have thought it should go after the parameter list. See http://clang.llvm.org/docs/AttributeReference.html#function-attributes

But if it works, that's fine.

3347 ↗(On Diff #44526)

Same comment as #3197

Moving the macro to the end of the parameter list works fine using clang.

Yep, just finished testing. Let's do that since its consistent with the
reference.

The macro is in __config

mclow.lists accepted this revision.Jan 11 2016, 11:18 AM
mclow.lists edited edge metadata.

Can you commit this, or do you need me to do so?

This revision is now accepted and ready to land.Jan 11 2016, 11:18 AM
danielaustin accepted this revision.Jan 11 2016, 11:19 AM
danielaustin added a reviewer: danielaustin.

Never tried, probably will need you do as I see no obvious commit option
for me.

landed as revision 257368.

danielaustin edited edge metadata.

Yep, I rock. Missed the right location to activate this for clang. This diff fixes that issue.

And I think that for clang, the actual flag you want is no_sanitize("unsigned-integer-overflow")

They both have the same effect on the target I am working with. I'm ok with
changing it if that's more proper than what I have.

On Mac OS, "unsigned integer" gives a warning.

warning: unknown sanitizer 'unsigned integer' ignored [-Wunknown-sanitizers]

landed as revision 257422

EricWF edited edge metadata.Jan 26 2016, 12:40 PM

Can we close this revision?

mclow.lists closed this revision.Jan 26 2016, 1:07 PM