Author: Jonas Devlieghere Date: 2020-07-07T10:13:41-07:00 New Revision: 5e9b16b67f5b9543e8d22b5b0f22cc0980c310bd
URL: https://github.com/llvm/llvm-project/commit/5e9b16b67f5b9543e8d22b5b0f22cc0980c310bd DIFF: https://github.com/llvm/llvm-project/commit/5e9b16b67f5b9543e8d22b5b0f22cc0980c310bd.diff LOG: [lldb] Fix unaligned load in DataExtractor Somehow UBSan would only report the unaligned load in TestLinuxCore.py when running the tests with reproducers. This patch fixes the issue by using a memcpy in the GetDouble and the GetFloat method. Differential revision: https://reviews.llvm.org/D83256 Added: Modified: lldb/include/lldb/Utility/DataExtractor.h lldb/source/Utility/DataExtractor.cpp lldb/unittests/Utility/DataExtractorTest.cpp Removed: ################################################################################ diff --git a/lldb/include/lldb/Utility/DataExtractor.h b/lldb/include/lldb/Utility/DataExtractor.h index 8f82ae5af42d..0210af5cf6d1 100644 --- a/lldb/include/lldb/Utility/DataExtractor.h +++ b/lldb/include/lldb/Utility/DataExtractor.h @@ -9,12 +9,14 @@ #ifndef LLDB_UTILITY_DATAEXTRACTOR_H #define LLDB_UTILITY_DATAEXTRACTOR_H +#include "lldb/Utility/Endian.h" #include "lldb/lldb-defines.h" #include "lldb/lldb-enumerations.h" #include "lldb/lldb-forward.h" #include "lldb/lldb-types.h" #include "llvm/ADT/ArrayRef.h" #include "llvm/Support/DataExtractor.h" +#include "llvm/Support/SwapByteOrder.h" #include <cassert> #include <stdint.h> @@ -979,6 +981,21 @@ class DataExtractor { } protected: + template <typename T> T Get(lldb::offset_t *offset_ptr, T fail_value) const { + constexpr size_t src_size = sizeof(T); + T val = fail_value; + + const T *src = static_cast<const T *>(GetData(offset_ptr, src_size)); + if (!src) + return val; + + memcpy(&val, src, src_size); + if (m_byte_order != endian::InlHostByteOrder()) + llvm::sys::swapByteOrder(val); + + return val; + } + // Member variables const uint8_t *m_start; ///< A pointer to the first byte of data. const uint8_t diff --git a/lldb/source/Utility/DataExtractor.cpp b/lldb/source/Utility/DataExtractor.cpp index ac3662a8e3c8..64b878d7dee7 100644 --- a/lldb/source/Utility/DataExtractor.cpp +++ b/lldb/source/Utility/DataExtractor.cpp @@ -15,7 +15,6 @@ #include "lldb/Utility/DataBuffer.h" #include "lldb/Utility/DataBufferHeap.h" -#include "lldb/Utility/Endian.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/Log.h" #include "lldb/Utility/Stream.h" @@ -624,41 +623,11 @@ int64_t DataExtractor::GetMaxS64Bitfield(offset_t *offset_ptr, size_t size, } float DataExtractor::GetFloat(offset_t *offset_ptr) const { - typedef float float_type; - float_type val = 0.0; - const size_t src_size = sizeof(float_type); - const float_type *src = - static_cast<const float_type *>(GetData(offset_ptr, src_size)); - if (src) { - if (m_byte_order != endian::InlHostByteOrder()) { - const uint8_t *src_data = reinterpret_cast<const uint8_t *>(src); - uint8_t *dst_data = reinterpret_cast<uint8_t *>(&val); - for (size_t i = 0; i < sizeof(float_type); ++i) - dst_data[sizeof(float_type) - 1 - i] = src_data[i]; - } else { - val = *src; - } - } - return val; + return Get<float>(offset_ptr, 0.0f); } double DataExtractor::GetDouble(offset_t *offset_ptr) const { - typedef double float_type; - float_type val = 0.0; - const size_t src_size = sizeof(float_type); - const float_type *src = - static_cast<const float_type *>(GetData(offset_ptr, src_size)); - if (src) { - if (m_byte_order != endian::InlHostByteOrder()) { - const uint8_t *src_data = reinterpret_cast<const uint8_t *>(src); - uint8_t *dst_data = reinterpret_cast<uint8_t *>(&val); - for (size_t i = 0; i < sizeof(float_type); ++i) - dst_data[sizeof(float_type) - 1 - i] = src_data[i]; - } else { - val = *src; - } - } - return val; + return Get<double>(offset_ptr, 0.0); } long double DataExtractor::GetLongDouble(offset_t *offset_ptr) const { diff --git a/lldb/unittests/Utility/DataExtractorTest.cpp b/lldb/unittests/Utility/DataExtractorTest.cpp index 109c15297b16..536e69755d17 100644 --- a/lldb/unittests/Utility/DataExtractorTest.cpp +++ b/lldb/unittests/Utility/DataExtractorTest.cpp @@ -299,3 +299,105 @@ TEST(DataExtractorTest, GetULEB128_bit63) { EXPECT_EQ(expected, BE.GetULEB128(&offset)); EXPECT_EQ(9U, offset); } + +TEST(DataExtractorTest, GetFloat) { + float expected = 4.0f; + lldb::offset_t offset; + + { + uint8_t buffer[] = {0x00, 0x00, 0x80, 0x40}; + DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle, + sizeof(void *)); + + offset = 0; + EXPECT_DOUBLE_EQ(expected, LE.GetFloat(&offset)); + EXPECT_EQ(4U, offset); + } + + { + uint8_t buffer[] = {0x40, 0x80, 0x00, 0x00}; + DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, + sizeof(void *)); + offset = 0; + EXPECT_DOUBLE_EQ(expected, BE.GetFloat(&offset)); + EXPECT_EQ(4U, offset); + } +} + +TEST(DataExtractorTest, GetFloatUnaligned) { + float expected = 4.0f; + lldb::offset_t offset; + + { + uint8_t buffer[] = {0x00, 0x00, 0x00, 0x80, 0x40}; + DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle, + sizeof(void *)); + + offset = 1; + EXPECT_DOUBLE_EQ(expected, LE.GetFloat(&offset)); + EXPECT_EQ(5U, offset); + } + + { + uint8_t buffer[] = {0x00, 0x40, 0x80, 0x00, 0x00}; + DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, + sizeof(void *)); + offset = 1; + EXPECT_DOUBLE_EQ(expected, BE.GetFloat(&offset)); + EXPECT_EQ(5U, offset); + } +} + +TEST(DataExtractorTest, GetDouble) { + if (sizeof(double) != 8) + return; + + double expected = 4.0f; + lldb::offset_t offset; + + { + uint8_t buffer[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40}; + DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle, + sizeof(void *)); + + offset = 0; + EXPECT_DOUBLE_EQ(expected, LE.GetDouble(&offset)); + EXPECT_EQ(8U, offset); + } + + { + uint8_t buffer[] = {0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, + sizeof(void *)); + offset = 0; + EXPECT_DOUBLE_EQ(expected, BE.GetDouble(&offset)); + EXPECT_EQ(8U, offset); + } +} + +TEST(DataExtractorTest, GetDoubleUnaligned) { + if (sizeof(double) != 8) + return; + + float expected = 4.0f; + lldb::offset_t offset; + + { + uint8_t buffer[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40}; + DataExtractor LE(buffer, sizeof(buffer), lldb::eByteOrderLittle, + sizeof(void *)); + + offset = 1; + EXPECT_DOUBLE_EQ(expected, LE.GetDouble(&offset)); + EXPECT_EQ(9U, offset); + } + + { + uint8_t buffer[] = {0x00, 0x40, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; + DataExtractor BE(buffer, sizeof(buffer), lldb::eByteOrderBig, + sizeof(void *)); + offset = 1; + EXPECT_DOUBLE_EQ(expected, BE.GetDouble(&offset)); + EXPECT_EQ(9U, offset); + } +} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits