| 24 | return false; |
| 25 | } |
| 26 | bool Checker::is_valid_dereference(const QueueItem & item, const CheckedStructure & cs, size_t size, bool quiet) |
| 27 | { |
| 28 | auto base = const_cast<void *>(item.ptr); |
| 29 | if (!base) |
| 30 | { |
| 31 | // cannot dereference null pointer, but not an error |
| 32 | return false; |
| 33 | } |
| 34 | |
| 35 | // assumes MALLOC_PERTURB_=45 |
| 36 | #ifdef DFHACK64 |
| 37 | #define UNINIT_PTR 0xd2d2d2d2d2d2d2d2 |
| 38 | #define FAIL_PTR(message) FAIL(fmt::format("{:#016x} ", reinterpret_cast<uintptr_t>(base)) << message) |
| 39 | #else |
| 40 | #define UNINIT_PTR 0xd2d2d2d2 |
| 41 | #define FAIL_PTR(message) FAIL(fmt::format("{:#016x} ", reinterpret_cast<uintptr_t>(base)) << message) |
| 42 | #endif |
| 43 | if (uintptr_t(base) == UNINIT_PTR) |
| 44 | { |
| 45 | if (!quiet) |
| 46 | { |
| 47 | FAIL_PTR("uninitialized pointer"); |
| 48 | } |
| 49 | return false; |
| 50 | } |
| 51 | |
| 52 | bool found = true; |
| 53 | auto expected_start = base; |
| 54 | size_t remaining_size = size; |
| 55 | while (found) |
| 56 | { |
| 57 | found = false; |
| 58 | |
| 59 | for (auto & range : mapped) |
| 60 | { |
| 61 | if (!range.isInRange(expected_start)) |
| 62 | { |
| 63 | continue; |
| 64 | } |
| 65 | |
| 66 | found = true; |
| 67 | |
| 68 | if (!range.valid || !range.read) |
| 69 | { |
| 70 | if (!quiet) |
| 71 | { |
| 72 | FAIL_PTR("pointer to invalid memory range"); |
| 73 | } |
| 74 | return false; |
| 75 | } |
| 76 | |
| 77 | auto expected_end = const_cast<void *>(PTR_ADD(expected_start, remaining_size - 1)); |
| 78 | if (size && !range.isInRange(expected_end)) |
| 79 | { |
| 80 | auto next_start = PTR_ADD(range.end, 1); |
| 81 | remaining_size -= ptrdiff_t(next_start) - ptrdiff_t(expected_start); |
| 82 | expected_start = const_cast<void *>(next_start); |
| 83 | break; |