| 147 | } |
| 148 | |
| 149 | const char *Checker::get_vtable_name(const QueueItem & item, const CheckedStructure & cs, bool quiet) |
| 150 | { |
| 151 | auto vtable = validate_and_dereference<const void *const*>(QueueItem(item, "?vtable?", item.ptr), quiet); |
| 152 | if (!vtable) |
| 153 | return nullptr; |
| 154 | |
| 155 | auto info = validate_and_dereference<const char *const*>(QueueItem(item, "?vtable?.info", vtable - 1), quiet); |
| 156 | if (!info) |
| 157 | return nullptr; |
| 158 | |
| 159 | #ifdef WIN32 |
| 160 | #ifdef DFHACK64 |
| 161 | void *base; |
| 162 | if (!RtlPcToFileHeader(const_cast<void *>(reinterpret_cast<const void *>(info)), &base)) |
| 163 | return nullptr; |
| 164 | |
| 165 | const char *typeinfo = reinterpret_cast<const char *>(base) + reinterpret_cast<const int32_t *>(info)[3]; |
| 166 | const char *name = typeinfo + 16; |
| 167 | #else |
| 168 | const char *name = reinterpret_cast<const char *>(info) + 8; |
| 169 | #endif |
| 170 | #else |
| 171 | auto name = validate_and_dereference<const char *>(QueueItem(item, "?vtable?.info.name", info + 1), quiet); |
| 172 | #endif |
| 173 | |
| 174 | for (auto & range : mapped) |
| 175 | { |
| 176 | if (!range.isInRange(const_cast<char *>(name))) |
| 177 | { |
| 178 | continue; |
| 179 | } |
| 180 | |
| 181 | if (!range.valid || !range.read) |
| 182 | { |
| 183 | if (!quiet) |
| 184 | { |
| 185 | FAIL("pointer to invalid memory range"); |
| 186 | } |
| 187 | return nullptr; |
| 188 | } |
| 189 | |
| 190 | const char *first_letter = nullptr; |
| 191 | bool letter = false; |
| 192 | for (const char *p = name; ; p++) |
| 193 | { |
| 194 | if (!range.isInRange(const_cast<char *>(p))) |
| 195 | { |
| 196 | return nullptr; |
| 197 | } |
| 198 | |
| 199 | if ((*p >= 'a' && *p <= 'z') || *p == '_') |
| 200 | { |
| 201 | if (!letter) |
| 202 | { |
| 203 | first_letter = p; |
| 204 | } |
| 205 | letter = true; |
| 206 | } |