Add additional effiency checks to sanity checker

This commit is contained in:
Pieter Wuille 2020-04-03 11:09:21 -07:00
parent fffd8dca2d
commit c81aefc537

View file

@ -126,11 +126,14 @@ bool SanityCheckASMap(const std::vector<bool>& asmap, int bits)
std::vector<bool>::const_iterator pos = begin; std::vector<bool>::const_iterator pos = begin;
std::vector<std::pair<uint32_t, int>> jumps; // All future positions we may jump to (bit offset in asmap -> bits to consume left) std::vector<std::pair<uint32_t, int>> jumps; // All future positions we may jump to (bit offset in asmap -> bits to consume left)
jumps.reserve(bits); jumps.reserve(bits);
Instruction prevopcode = Instruction::JUMP;
bool had_incomplete_match = false;
while (pos != endpos) { while (pos != endpos) {
uint32_t offset = pos - begin; uint32_t offset = pos - begin;
if (!jumps.empty() && offset >= jumps.back().first) return false; // There was a jump into the middle of the previous instruction if (!jumps.empty() && offset >= jumps.back().first) return false; // There was a jump into the middle of the previous instruction
Instruction opcode = DecodeType(pos, endpos); Instruction opcode = DecodeType(pos, endpos);
if (opcode == Instruction::RETURN) { if (opcode == Instruction::RETURN) {
if (prevopcode == Instruction::DEFAULT) return false; // There should not be any RETURN immediately after a DEFAULT (could be combined into just RETURN)
uint32_t asn = DecodeASN(pos, endpos); uint32_t asn = DecodeASN(pos, endpos);
if (asn == INVALID) return false; // ASN straddles EOF if (asn == INVALID) return false; // ASN straddles EOF
if (jumps.empty()) { if (jumps.empty()) {
@ -147,6 +150,7 @@ bool SanityCheckASMap(const std::vector<bool>& asmap, int bits)
if (offset != jumps.back().first) return false; // Unreachable code if (offset != jumps.back().first) return false; // Unreachable code
bits = jumps.back().second; // Restore the number of bits we would have had left after this jump bits = jumps.back().second; // Restore the number of bits we would have had left after this jump
jumps.pop_back(); jumps.pop_back();
prevopcode = Instruction::JUMP;
} }
} else if (opcode == Instruction::JUMP) { } else if (opcode == Instruction::JUMP) {
uint32_t jump = DecodeJump(pos, endpos); uint32_t jump = DecodeJump(pos, endpos);
@ -157,15 +161,22 @@ bool SanityCheckASMap(const std::vector<bool>& asmap, int bits)
uint32_t jump_offset = pos - begin + jump; uint32_t jump_offset = pos - begin + jump;
if (!jumps.empty() && jump_offset >= jumps.back().first) return false; // Intersecting jumps if (!jumps.empty() && jump_offset >= jumps.back().first) return false; // Intersecting jumps
jumps.emplace_back(jump_offset, bits); jumps.emplace_back(jump_offset, bits);
prevopcode = Instruction::JUMP;
} else if (opcode == Instruction::MATCH) { } else if (opcode == Instruction::MATCH) {
uint32_t match = DecodeMatch(pos, endpos); uint32_t match = DecodeMatch(pos, endpos);
if (match == INVALID) return false; // Match bits straddle EOF if (match == INVALID) return false; // Match bits straddle EOF
int matchlen = CountBits(match) - 1; int matchlen = CountBits(match) - 1;
if (prevopcode != Instruction::MATCH) had_incomplete_match = false;
if (matchlen < 8 && had_incomplete_match) return false; // Within a sequence of matches only at most one should be incomplete
had_incomplete_match = (matchlen < 8);
if (bits < matchlen) return false; // Consuming bits past the end of the input if (bits < matchlen) return false; // Consuming bits past the end of the input
bits -= matchlen; bits -= matchlen;
prevopcode = Instruction::MATCH;
} else if (opcode == Instruction::DEFAULT) { } else if (opcode == Instruction::DEFAULT) {
if (prevopcode == Instruction::DEFAULT) return false; // There should not be two successive DEFAULTs (they could be combined into one)
uint32_t asn = DecodeASN(pos, endpos); uint32_t asn = DecodeASN(pos, endpos);
if (asn == INVALID) return false; // ASN straddles EOF if (asn == INVALID) return false; // ASN straddles EOF
prevopcode = Instruction::DEFAULT;
} else { } else {
return false; // Instruction straddles EOF return false; // Instruction straddles EOF
} }