| 1272 | } |
| 1273 | |
| 1274 | void ValidationContext::validateKVD() { |
| 1275 | const auto kvdByteOffset = header.keyValueData.byteOffset; |
| 1276 | const auto kvdByteLength = header.keyValueData.byteLength; |
| 1277 | |
| 1278 | if (kvdByteOffset == 0 || kvdByteLength == 0) |
| 1279 | return; // There is no KVD block |
| 1280 | |
| 1281 | const auto buffer = std::make_unique<uint8_t[]>(kvdByteLength); |
| 1282 | read(kvdByteOffset, buffer.get(), kvdByteLength, "the Key/Value Data"); |
| 1283 | const auto* ptrKVD = buffer.get(); |
| 1284 | const auto* ptrKVDEnd = ptrKVD + kvdByteLength; |
| 1285 | |
| 1286 | struct KeyValueEntry { |
| 1287 | std::string key; |
| 1288 | const uint8_t* data; |
| 1289 | uint32_t size; |
| 1290 | |
| 1291 | KeyValueEntry(std::string_view key, const uint8_t* data, uint32_t size) : |
| 1292 | key(key), data(data), size(size) {} |
| 1293 | }; |
| 1294 | std::vector<KeyValueEntry> entries; |
| 1295 | std::unordered_set<std::string_view> keys; |
| 1296 | |
| 1297 | uint32_t numKVEntry = 0; |
| 1298 | // Process Key-Value entries {size, key, \0, value} until the end of the KVD block |
| 1299 | // Where size is an uint32_t, and it equals to: sizeof(key) + 1 + sizeof(value) |
| 1300 | const auto* ptrEntry = ptrKVD; |
| 1301 | while (ptrEntry < ptrKVDEnd) { |
| 1302 | const auto remainingKVDBytes = ptrKVDEnd - ptrEntry; |
| 1303 | |
| 1304 | if (++numKVEntry > MAX_NUM_KV_ENTRIES) { |
| 1305 | warning(Metadata::TooManyEntries, numKVEntry - 1, remainingKVDBytes); |
| 1306 | ptrEntry = ptrKVDEnd; |
| 1307 | break; |
| 1308 | } |
| 1309 | |
| 1310 | if (remainingKVDBytes < 6) { |
| 1311 | error(Metadata::NotEnoughDataForAnEntry, remainingKVDBytes); |
| 1312 | ptrEntry = ptrKVDEnd; |
| 1313 | break; |
| 1314 | } |
| 1315 | |
| 1316 | uint32_t sizeKeyValuePair; |
| 1317 | std::memcpy(&sizeKeyValuePair, ptrEntry, sizeof(uint32_t)); |
| 1318 | |
| 1319 | const auto* ptrKeyValuePair = ptrEntry + sizeof(uint32_t); |
| 1320 | const auto* ptrKey = ptrKeyValuePair; |
| 1321 | |
| 1322 | if (sizeKeyValuePair < 2) { |
| 1323 | error(Metadata::KeyAndValueByteLengthTooSmall, sizeKeyValuePair); |
| 1324 | } else { |
| 1325 | if (ptrKeyValuePair + sizeKeyValuePair > ptrKVDEnd) { |
| 1326 | const auto bytesLeft = ptrKVDEnd - ptrKeyValuePair; |
| 1327 | error(Metadata::KeyAndValueByteLengthTooLarge, sizeKeyValuePair, bytesLeft); |
| 1328 | sizeKeyValuePair = static_cast<uint32_t>(bytesLeft); // Attempt recovery to read out at least the key |
| 1329 | } |
| 1330 | |
| 1331 | // Determine key, finding the null terminator |
nothing calls this directly
no test coverage detected