diff options
author | Eric Fiselier <eric@efcs.ca> | 2014-11-24 18:46:37 +0000 |
---|---|---|
committer | Eric Fiselier <eric@efcs.ca> | 2014-11-24 18:46:37 +0000 |
commit | 90c138ea6d47c363ee3f7b55f90239c46ba5cc2f (patch) | |
tree | 666c3f528217ddfef225932c72606ddc8236839f /libcxxabi | |
parent | 909deebfc8b90eee317424646f6bdf358160164e (diff) | |
download | llvm-90c138ea6d47c363ee3f7b55f90239c46ba5cc2f.zip llvm-90c138ea6d47c363ee3f7b55f90239c46ba5cc2f.tar.gz llvm-90c138ea6d47c363ee3f7b55f90239c46ba5cc2f.tar.bz2 |
[libcxxabi] Delay adjustment of pointer to prevent referencing invalid memory.
Summary:
This patch delays the dereference adjustment until we are sure the thrown type is a pointer type. It is possible the thrown type is not a pointer and is smaller than `sizeof(void*)`. If the thrown type is is smaller than `sizeof(void*)` the deference adjustment will result in a heap buffer overflow.
I audited all the call sites of `can_catch(...)` and there are no places where `adjustedPtr` is used if `can_catch(...)` returns false. For this reason the patch should not introduce any functionality change.
This patch fixes the following tests when using ASAN:
* unwind_01.cpp
* unwind_02.cpp
* unwind_04.cpp
Reviewers: danalbert, jroelofs, mclow.lists
Reviewed By: mclow.lists
Subscribers: cfe-commits
Differential Revision: http://reviews.llvm.org/D6353
llvm-svn: 222674
Diffstat (limited to 'libcxxabi')
-rw-r--r-- | libcxxabi/src/private_typeinfo.cpp | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/libcxxabi/src/private_typeinfo.cpp b/libcxxabi/src/private_typeinfo.cpp index a4699ff..38e70ab 100644 --- a/libcxxabi/src/private_typeinfo.cpp +++ b/libcxxabi/src/private_typeinfo.cpp @@ -347,30 +347,34 @@ bool __pbase_type_info::can_catch(const __shim_type_info* thrown_type, void*&) const { - if (is_equal(this, thrown_type, false)) - return true; - return is_equal(thrown_type, &typeid(std::nullptr_t), false); + return is_equal(this, thrown_type, false) || + is_equal(thrown_type, &typeid(std::nullptr_t), false); } #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wmissing-field-initializers" // Handles bullets 1, 3 and 4 +// NOTE: It might not be safe to adjust the pointer if it is not not a pointer +// type. Only adjust the pointer after we know it is safe to do so. bool __pointer_type_info::can_catch(const __shim_type_info* thrown_type, void*& adjustedPtr) const { - // Do the dereference adjustment - if (adjustedPtr != NULL) - adjustedPtr = *static_cast<void**>(adjustedPtr); // bullets 1 and 4 - if (__pbase_type_info::can_catch(thrown_type, adjustedPtr)) + if (__pbase_type_info::can_catch(thrown_type, adjustedPtr)) { + if (adjustedPtr != NULL) + adjustedPtr = *static_cast<void**>(adjustedPtr); return true; + } // bullet 3 const __pointer_type_info* thrown_pointer_type = dynamic_cast<const __pointer_type_info*>(thrown_type); if (thrown_pointer_type == 0) return false; + // Do the dereference adjustment + if (adjustedPtr != NULL) + adjustedPtr = *static_cast<void**>(adjustedPtr); // bullet 3B if (thrown_pointer_type->__flags & ~__flags) return false; |