[Lldb-commits] [PATCH] D73913: [lldb/DataExtractor] Fix UB shift in GetMaxS64Bitfield

Vedant Kumar via Phabricator via lldb-commits lldb-commits at lists.llvm.org
Mon Feb 3 11:29:45 PST 2020


vsk created this revision.
vsk added reviewers: labath, JDevlieghere, teemperor.

DataExtractor::GetMaxS64Bitfield performs a shift with UB in order to
construct a bitmask when bitfield_bit_size is 64. The current
implementation actually does “work” in this case, because the assumption
that the shift result is 0 holds, and 0 minus 1 gives the all-ones value
(the correct mask). However, the more readable/maintainable approach
might be to use an off-the-shelf UB-free helper.

Fixes a UBSan issue:

  "col" : 37,
  "description" : "invalid-shift-exponent",
  "filename" : "/Users/vsk/src/llvm-project-master/lldb/source/Utility/DataExtractor.cpp",
  "instrumentation_class" : "UndefinedBehaviorSanitizer",
  "line" : 615,
  "memory_address" : 0,
  "summary" : "Shift exponent 64 is too large for 64-bit type 'uint64_t' (aka 'unsigned long long')",

rdar://59117758


https://reviews.llvm.org/D73913

Files:
  lldb/include/lldb/Utility/DataExtractor.h
  lldb/source/Utility/DataExtractor.cpp
  lldb/unittests/Utility/DataExtractorTest.cpp


Index: lldb/unittests/Utility/DataExtractorTest.cpp
===================================================================
--- lldb/unittests/Utility/DataExtractorTest.cpp
+++ lldb/unittests/Utility/DataExtractorTest.cpp
@@ -25,6 +25,9 @@
   offset = 0;
   ASSERT_EQ(buffer[1], BE.GetMaxU64Bitfield(&offset, sizeof(buffer), 8, 8));
   offset = 0;
+  ASSERT_EQ(static_cast<uint64_t>(0xEFCDAB8967452301),
+            LE.GetMaxU64Bitfield(&offset, sizeof(buffer), 64, 0));
+  offset = 0;
   ASSERT_EQ(static_cast<uint64_t>(0x0123456789ABCDEF),
             BE.GetMaxU64Bitfield(&offset, sizeof(buffer), 64, 0));
   offset = 0;
@@ -40,6 +43,12 @@
   offset = 0;
   ASSERT_EQ(int8_t(buffer[1]),
             BE.GetMaxS64Bitfield(&offset, sizeof(buffer), 8, 8));
+  offset = 0;
+  ASSERT_EQ(static_cast<int64_t>(0xEFCDAB8967452301),
+            LE.GetMaxS64Bitfield(&offset, sizeof(buffer), 64, 0));
+  offset = 0;
+  ASSERT_EQ(static_cast<int64_t>(0x0123456789ABCDEF),
+            BE.GetMaxS64Bitfield(&offset, sizeof(buffer), 64, 0));
 }
 
 TEST(DataExtractorTest, PeekData) {
Index: lldb/source/Utility/DataExtractor.cpp
===================================================================
--- lldb/source/Utility/DataExtractor.cpp
+++ lldb/source/Utility/DataExtractor.cpp
@@ -604,6 +604,8 @@
 int64_t DataExtractor::GetMaxS64Bitfield(offset_t *offset_ptr, size_t size,
                                          uint32_t bitfield_bit_size,
                                          uint32_t bitfield_bit_offset) const {
+  assert(size >= 1 && "GetMaxS64Bitfield size must be >= 1");
+  assert(size <= 8 && "GetMaxS64Bitfield size must be <= 8");
   int64_t sval64 = GetMaxS64(offset_ptr, size);
   if (bitfield_bit_size > 0) {
     int32_t lsbcount = bitfield_bit_offset;
@@ -612,7 +614,7 @@
     if (lsbcount > 0)
       sval64 >>= lsbcount;
     uint64_t bitfield_mask =
-        ((static_cast<uint64_t>(1)) << bitfield_bit_size) - 1;
+        llvm::maskTrailingOnes<uint64_t>(bitfield_bit_size);
     sval64 &= bitfield_mask;
     // sign extend if needed
     if (sval64 & ((static_cast<uint64_t>(1)) << (bitfield_bit_size - 1)))
Index: lldb/include/lldb/Utility/DataExtractor.h
===================================================================
--- lldb/include/lldb/Utility/DataExtractor.h
+++ lldb/include/lldb/Utility/DataExtractor.h
@@ -535,13 +535,13 @@
                              uint32_t bitfield_bit_size,
                              uint32_t bitfield_bit_offset) const;
 
-  /// Extract an signed integer of size \a byte_size from \a *offset_ptr, then
-  /// extract and signe extend the bitfield from this value if \a
+  /// Extract an signed integer of size \a size from \a *offset_ptr, then
+  /// extract and sign-extend the bitfield from this value if \a
   /// bitfield_bit_size is non-zero.
   ///
-  /// Extract a single signed integer value (sign extending if required) and
+  /// Extract a single signed integer value (sign-extending if required) and
   /// update the offset pointed to by \a offset_ptr. The size of the extracted
-  /// integer is specified by the \a byte_size argument. \a byte_size must
+  /// integer is specified by the \a size argument. \a size must
   /// have a value greater than or equal to one and less than or equal to
   /// eight since the return value is 64 bits wide.
   ///


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D73913.242140.patch
Type: text/x-patch
Size: 3335 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/lldb-commits/attachments/20200203/25a57efd/attachment.bin>


More information about the lldb-commits mailing list