Commit 0752c055 authored by Alastair Harrison's avatar Alastair Harrison Committed by Facebook Github Bot

Fix libc++ ASAN failures in resizeWithoutInitialization (#1194)

Summary:
This is a proposed fix for issue: https://github.com/facebook/folly/issues/1193
Using `folly::resizeWithoutInitialization` with libc++ and the address sanitizer causes false positive 'container overflow' failures.

This PR only addresses the problem for resizing `std::vector`. Presumably the version of `folly::resizeWithoutInitialization` for `std::string` has the same problem, but I have not verified this.

### Potential issues
This PR assumes that the `__sanitizer_annotate_contiguous_container` is available in libc++, and that the `std::vector` implementation has been annotated with it. The latter occurred in ~2014:
http://llvm.org/viewvc/llvm-project/libcxx/trunk/include/vector?r1=191987&r2=208319&pathrev=208319

If there are people using C++14 compilers with versions of libc++ predating the addition of the `std::vector<T>::__annotate_contiguous_container` member function then this fix will fail to compile.

I'm not aware of any sane way to detect the exact version of libc++ being used. Perhaps a suitable mitigation for those (few?) people with a C++14 compiler and pre-2015 libc++ implementation would be to provide a `FOLLY_` macro to disable the annotation.
Pull Request resolved: https://github.com/facebook/folly/pull/1194

Reviewed By: yfeldblum

Differential Revision: D16445890

Pulled By: nbronson

fbshipit-source-id: ef33bbd5cc12c71822985c5174bf8e47e6eb3757
parent 32767e68
......@@ -264,7 +264,13 @@ inline void unsafeStringSetLargerSize(std::string& s, std::size_t n) {
#if defined(_LIBCPP_VECTOR)
// libc++
template <typename Tag, typename T, typename A, A Ptr__end_>
template <
typename Tag,
typename T,
typename A,
A Ptr__end_,
typename B,
B Ptr__annotate_contiguous_container_>
struct MakeUnsafeVectorSetLargerSize {
friend void unsafeVectorSetLargerSizeImpl(std::vector<T>& v, std::size_t n) {
// v.__end_ += (n - v.size());
......@@ -273,16 +279,31 @@ struct MakeUnsafeVectorSetLargerSize {
std::is_standard_layout<std::vector<T>>::value &&
sizeof(std::vector<T>) == sizeof(Base),
"reinterpret_cast safety conditions not met");
const auto old_size = v.size();
reinterpret_cast<Base&>(v).*Ptr__end_ += (n - v.size());
// libc++ contiguous containers use special annotation functions that help
// the address sanitizer to detect improper memory accesses. When ASAN is
// enabled we need to call the appropriate annotation functions in order to
// stop ASAN from reporting false positives. When ASAN is disabled, the
// annotation function is a no-op.
(v.*Ptr__annotate_contiguous_container_)(
v.data(),
v.data() + v.capacity(),
v.data() + old_size,
v.data() + v.size());
}
};
#define FOLLY_DECLARE_VECTOR_RESIZE_WITHOUT_INIT(TYPE) \
template struct folly::detail::MakeUnsafeVectorSetLargerSize< \
FollyMemoryDetailTranslationUnitTag, \
TYPE, \
TYPE*(std::__vector_base<TYPE, std::allocator<TYPE>>::*), \
&std::vector<TYPE>::__end_>; \
#define FOLLY_DECLARE_VECTOR_RESIZE_WITHOUT_INIT(TYPE) \
template struct folly::detail::MakeUnsafeVectorSetLargerSize< \
FollyMemoryDetailTranslationUnitTag, \
TYPE, \
TYPE*(std::__vector_base<TYPE, std::allocator<TYPE>>::*), \
&std::vector<TYPE>::__end_, \
void (std::vector<TYPE>::*)( \
const void*, const void*, const void*, const void*) const, \
&std::vector<TYPE>::__annotate_contiguous_container>; \
FOLLY_DECLARE_VECTOR_RESIZE_WITHOUT_INIT_IMPL(TYPE)
#elif defined(_GLIBCXX_VECTOR)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment