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