Merge pull request #3616 from lethosor/check-structures-sanity-fix-string-cxx11

check-structures-sanity: update detection for GCC C++11 std::string
develop
Myk 2023-07-31 23:13:31 -07:00 committed by GitHub
commit 876de86066
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 24 additions and 40 deletions

@ -1,5 +1,7 @@
#include "check-structures-sanity.h" #include "check-structures-sanity.h"
#include <cinttypes>
#include "df/large_integer.h" #include "df/large_integer.h"
Checker::Checker(color_ostream & out) : Checker::Checker(color_ostream & out) :
@ -845,69 +847,51 @@ void Checker::check_stl_string(const QueueItem & item)
#else #else
struct string_data struct string_data
{ {
struct string_data_inner uintptr_t start;
size_t length;
union
{ {
size_t length; char local_data[16];
size_t capacity; size_t capacity;
int32_t refcount; };
} *ptr;
}; };
#endif #endif
auto string = reinterpret_cast<const string_data *>(item.ptr); auto string = reinterpret_cast<const string_data *>(item.ptr);
#ifdef WIN32 #ifdef WIN32
bool is_local = string->capacity < 16; const bool is_gcc = false;
const bool is_local = string->capacity < 16;
#else
const bool is_gcc = true;
const bool is_local = string->start == reinterpret_cast<uintptr_t>(&string->local_data[0]);
#endif
const char *start = is_local ? &string->local_data[0] : reinterpret_cast<const char *>(string->start); const char *start = is_local ? &string->local_data[0] : reinterpret_cast<const char *>(string->start);
ptrdiff_t length = string->length; ptrdiff_t length = string->length;
ptrdiff_t capacity = string->capacity; ptrdiff_t capacity = string->capacity;
#else
if (!is_valid_dereference(QueueItem(item, "?ptr?", string->ptr), 1)) (void)start;
if (length < 0)
{ {
// nullptr is NOT okay here FAIL("string length is negative (" << length << ")");
FAIL("invalid string pointer " << stl_sprintf("%p", string->ptr));
return;
} }
if (!is_valid_dereference(QueueItem(item, "?hdr?", string->ptr - 1), sizeof(*string->ptr))) else if (is_gcc && length > 0 && !is_valid_dereference(QueueItem(item, "?start?", reinterpret_cast<void *>(string->start)), 1))
{ {
// nullptr is NOT okay here
FAIL("invalid string pointer " << stl_sprintf("0x%" PRIxPTR, string->start));
return; return;
} }
const char *start = reinterpret_cast<const char *>(string->ptr); else if (is_local && length >= 16)
ptrdiff_t length = (string->ptr - 1)->length;
ptrdiff_t capacity = (string->ptr - 1)->capacity;
#endif
(void)start;
if (length < 0)
{ {
FAIL("string length is negative (" << length << ")"); FAIL("string length is too large for small string (" << length << ")");
} }
else if (capacity < 0) else if ((!is_gcc || !is_local) && capacity < 0)
{ {
FAIL("string capacity is negative (" << capacity << ")"); FAIL("string capacity is negative (" << capacity << ")");
} }
else if (capacity < length) else if ((!is_gcc || !is_local) && capacity < length)
{ {
FAIL("string capacity (" << capacity << ") is less than length (" << length << ")"); FAIL("string capacity (" << capacity << ") is less than length (" << length << ")");
} }
#ifndef WIN32
const std::string empty_string;
auto empty_string_data = reinterpret_cast<const string_data *>(&empty_string);
if (sizes && string->ptr != empty_string_data->ptr)
{
size_t allocated_size = get_allocated_size(QueueItem(item, "?hdr?", string->ptr - 1));
size_t expected_size = sizeof(*string->ptr) + capacity + 1;
if (!allocated_size)
{
FAIL("pointer does not appear to be a string");
}
else if (allocated_size != expected_size)
{
FAIL("allocated string data size (" << allocated_size << ") does not match expected size (" << expected_size << ")");
}
}
#endif
} }
void Checker::check_possible_pointer(const QueueItem & item, const CheckedStructure & cs) void Checker::check_possible_pointer(const QueueItem & item, const CheckedStructure & cs)
{ {