From 31b94114c0921725317e678ab9a02f60001f3288 Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Mon, 27 Jul 2020 13:12:17 +0200 Subject: [PATCH] UserspaceEmulator: Recognize xor/sub zeroing idioms and don't taint "xor reg,reg" or "sub reg,reg" both zero out the register, which means we know for sure the result is 0. So mark the value as initialized, and make sure we don't taint the CPU flags. This removes some false positives from the uninitialized memory use detection mechanism. Fixes #2850. --- DevTools/UserspaceEmulator/SoftCPU.cpp | 88 +++++++++++++------- DevTools/UserspaceEmulator/SoftCPU.h | 12 +-- DevTools/UserspaceEmulator/ValueWithShadow.h | 10 +++ 3 files changed, 72 insertions(+), 38 deletions(-) diff --git a/DevTools/UserspaceEmulator/SoftCPU.cpp b/DevTools/UserspaceEmulator/SoftCPU.cpp index 6edb92358b..5cdbd24d3a 100644 --- a/DevTools/UserspaceEmulator/SoftCPU.cpp +++ b/DevTools/UserspaceEmulator/SoftCPU.cpp @@ -761,12 +761,16 @@ ALWAYS_INLINE void SoftCPU::generic_RM16_unsigned_imm8(Op op, const X86::Instruc insn.modrm().write16(*this, insn, result); } -template +template ALWAYS_INLINE void SoftCPU::generic_RM16_reg16(Op op, const X86::Instruction& insn) { auto dest = insn.modrm().read16>(*this, insn); auto src = const_gpr16(insn.reg16()); auto result = op(*this, dest, src); + if (dont_taint_for_same_operand && insn.modrm().is_register() && insn.modrm().register_index() == insn.register_index()) { + result.set_initialized(); + m_flags_tainted = false; + } if (update_dest) insn.modrm().write16(*this, insn, result); } @@ -801,12 +805,16 @@ ALWAYS_INLINE void SoftCPU::generic_RM32_unsigned_imm8(Op op, const X86::Instruc insn.modrm().write32(*this, insn, result); } -template +template ALWAYS_INLINE void SoftCPU::generic_RM32_reg32(Op op, const X86::Instruction& insn) { auto dest = insn.modrm().read32>(*this, insn); auto src = const_gpr32(insn.reg32()); auto result = op(*this, dest, src); + if (dont_taint_for_same_operand && insn.modrm().is_register() && insn.modrm().register_index() == insn.register_index()) { + result.set_initialized(); + m_flags_tainted = false; + } if (update_dest) insn.modrm().write32(*this, insn, result); } @@ -821,42 +829,58 @@ ALWAYS_INLINE void SoftCPU::generic_RM8_imm8(Op op, const X86::Instruction& insn insn.modrm().write8(*this, insn, result); } -template +template ALWAYS_INLINE void SoftCPU::generic_RM8_reg8(Op op, const X86::Instruction& insn) { auto dest = insn.modrm().read8>(*this, insn); auto src = const_gpr8(insn.reg8()); auto result = op(*this, dest, src); + if (dont_taint_for_same_operand && insn.modrm().is_register() && insn.modrm().register_index() == insn.register_index()) { + result.set_initialized(); + m_flags_tainted = false; + } if (update_dest) insn.modrm().write8(*this, insn, result); } -template +template ALWAYS_INLINE void SoftCPU::generic_reg16_RM16(Op op, const X86::Instruction& insn) { auto dest = const_gpr16(insn.reg16()); auto src = insn.modrm().read16>(*this, insn); auto result = op(*this, dest, src); + if (dont_taint_for_same_operand && insn.modrm().is_register() && insn.modrm().register_index() == insn.register_index()) { + result.set_initialized(); + m_flags_tainted = false; + } if (update_dest) gpr16(insn.reg16()) = result; } -template +template ALWAYS_INLINE void SoftCPU::generic_reg32_RM32(Op op, const X86::Instruction& insn) { auto dest = const_gpr32(insn.reg32()); auto src = insn.modrm().read32>(*this, insn); auto result = op(*this, dest, src); + if (dont_taint_for_same_operand && insn.modrm().is_register() && insn.modrm().register_index() == insn.register_index()) { + result.set_initialized(); + m_flags_tainted = false; + } if (update_dest) gpr32(insn.reg32()) = result; } -template +template ALWAYS_INLINE void SoftCPU::generic_reg8_RM8(Op op, const X86::Instruction& insn) { auto dest = const_gpr8(insn.reg8()); auto src = insn.modrm().read8>(*this, insn); auto result = op(*this, dest, src); + if (dont_taint_for_same_operand && insn.modrm().is_register() && insn.modrm().register_index() == insn.register_index()) { + result.set_initialized(); + m_flags_tainted = false; + } if (update_dest) gpr8(insn.reg8()) = result; } @@ -2506,34 +2530,34 @@ void SoftCPU::XLAT(const X86::Instruction& insn) set_al(read_memory8({ segment(insn.segment_prefix().value_or(X86::SegmentRegister::DS)), offset })); } -#define DEFINE_GENERIC_INSN_HANDLERS_PARTIAL(mnemonic, op, update_dest) \ - void SoftCPU::mnemonic##_AL_imm8(const X86::Instruction& insn) { generic_AL_imm8(op>, insn); } \ - void SoftCPU::mnemonic##_AX_imm16(const X86::Instruction& insn) { generic_AX_imm16(op>, insn); } \ - void SoftCPU::mnemonic##_EAX_imm32(const X86::Instruction& insn) { generic_EAX_imm32(op>, insn); } \ - void SoftCPU::mnemonic##_RM16_imm16(const X86::Instruction& insn) { generic_RM16_imm16(op>, insn); } \ - void SoftCPU::mnemonic##_RM16_reg16(const X86::Instruction& insn) { generic_RM16_reg16(op>, insn); } \ - void SoftCPU::mnemonic##_RM32_imm32(const X86::Instruction& insn) { generic_RM32_imm32(op>, insn); } \ - void SoftCPU::mnemonic##_RM32_reg32(const X86::Instruction& insn) { generic_RM32_reg32(op>, insn); } \ - void SoftCPU::mnemonic##_RM8_imm8(const X86::Instruction& insn) { generic_RM8_imm8(op>, insn); } \ - void SoftCPU::mnemonic##_RM8_reg8(const X86::Instruction& insn) { generic_RM8_reg8(op>, insn); } +#define DEFINE_GENERIC_INSN_HANDLERS_PARTIAL(mnemonic, op, update_dest, is_zero_idiom_if_both_operands_same) \ + void SoftCPU::mnemonic##_AL_imm8(const X86::Instruction& insn) { generic_AL_imm8(op>, insn); } \ + void SoftCPU::mnemonic##_AX_imm16(const X86::Instruction& insn) { generic_AX_imm16(op>, insn); } \ + void SoftCPU::mnemonic##_EAX_imm32(const X86::Instruction& insn) { generic_EAX_imm32(op>, insn); } \ + void SoftCPU::mnemonic##_RM16_imm16(const X86::Instruction& insn) { generic_RM16_imm16(op>, insn); } \ + void SoftCPU::mnemonic##_RM16_reg16(const X86::Instruction& insn) { generic_RM16_reg16(op>, insn); } \ + void SoftCPU::mnemonic##_RM32_imm32(const X86::Instruction& insn) { generic_RM32_imm32(op>, insn); } \ + void SoftCPU::mnemonic##_RM32_reg32(const X86::Instruction& insn) { generic_RM32_reg32(op>, insn); } \ + void SoftCPU::mnemonic##_RM8_imm8(const X86::Instruction& insn) { generic_RM8_imm8(op>, insn); } \ + void SoftCPU::mnemonic##_RM8_reg8(const X86::Instruction& insn) { generic_RM8_reg8(op>, insn); } -#define DEFINE_GENERIC_INSN_HANDLERS(mnemonic, op, update_dest) \ - DEFINE_GENERIC_INSN_HANDLERS_PARTIAL(mnemonic, op, update_dest) \ - void SoftCPU::mnemonic##_RM16_imm8(const X86::Instruction& insn) { generic_RM16_imm8(op>, insn); } \ - void SoftCPU::mnemonic##_RM32_imm8(const X86::Instruction& insn) { generic_RM32_imm8(op>, insn); } \ - void SoftCPU::mnemonic##_reg16_RM16(const X86::Instruction& insn) { generic_reg16_RM16(op>, insn); } \ - void SoftCPU::mnemonic##_reg32_RM32(const X86::Instruction& insn) { generic_reg32_RM32(op>, insn); } \ - void SoftCPU::mnemonic##_reg8_RM8(const X86::Instruction& insn) { generic_reg8_RM8(op>, insn); } +#define DEFINE_GENERIC_INSN_HANDLERS(mnemonic, op, update_dest, is_zero_idiom_if_both_operands_same) \ + DEFINE_GENERIC_INSN_HANDLERS_PARTIAL(mnemonic, op, update_dest, is_zero_idiom_if_both_operands_same) \ + void SoftCPU::mnemonic##_RM16_imm8(const X86::Instruction& insn) { generic_RM16_imm8(op>, insn); } \ + void SoftCPU::mnemonic##_RM32_imm8(const X86::Instruction& insn) { generic_RM32_imm8(op>, insn); } \ + void SoftCPU::mnemonic##_reg16_RM16(const X86::Instruction& insn) { generic_reg16_RM16(op>, insn); } \ + void SoftCPU::mnemonic##_reg32_RM32(const X86::Instruction& insn) { generic_reg32_RM32(op>, insn); } \ + void SoftCPU::mnemonic##_reg8_RM8(const X86::Instruction& insn) { generic_reg8_RM8(op>, insn); } -DEFINE_GENERIC_INSN_HANDLERS(XOR, op_xor, true) -DEFINE_GENERIC_INSN_HANDLERS(OR, op_or, true) -DEFINE_GENERIC_INSN_HANDLERS(ADD, op_add, true) -DEFINE_GENERIC_INSN_HANDLERS(ADC, op_adc, true) -DEFINE_GENERIC_INSN_HANDLERS(SUB, op_sub, true) -DEFINE_GENERIC_INSN_HANDLERS(SBB, op_sbb, true) -DEFINE_GENERIC_INSN_HANDLERS(AND, op_and, true) -DEFINE_GENERIC_INSN_HANDLERS(CMP, op_sub, false) -DEFINE_GENERIC_INSN_HANDLERS_PARTIAL(TEST, op_and, false) +DEFINE_GENERIC_INSN_HANDLERS(XOR, op_xor, true, true) +DEFINE_GENERIC_INSN_HANDLERS(OR, op_or, true, false) +DEFINE_GENERIC_INSN_HANDLERS(ADD, op_add, true, false) +DEFINE_GENERIC_INSN_HANDLERS(ADC, op_adc, true, false) +DEFINE_GENERIC_INSN_HANDLERS(SUB, op_sub, true, true) +DEFINE_GENERIC_INSN_HANDLERS(SBB, op_sbb, true, false) +DEFINE_GENERIC_INSN_HANDLERS(AND, op_and, true, false) +DEFINE_GENERIC_INSN_HANDLERS(CMP, op_sub, false, false) +DEFINE_GENERIC_INSN_HANDLERS_PARTIAL(TEST, op_and, false, false) void SoftCPU::MOVQ_mm1_mm2m64(const X86::Instruction&) { TODO(); } void SoftCPU::EMMS(const X86::Instruction&) { TODO(); } diff --git a/DevTools/UserspaceEmulator/SoftCPU.h b/DevTools/UserspaceEmulator/SoftCPU.h index 2acd0ff65c..8148dd8353 100644 --- a/DevTools/UserspaceEmulator/SoftCPU.h +++ b/DevTools/UserspaceEmulator/SoftCPU.h @@ -950,7 +950,7 @@ private: void generic_RM16_imm8(Op, const X86::Instruction&); template void generic_RM16_unsigned_imm8(Op, const X86::Instruction&); - template + template void generic_RM16_reg16(Op, const X86::Instruction&); template void generic_RM32_imm32(Op, const X86::Instruction&); @@ -958,17 +958,17 @@ private: void generic_RM32_imm8(Op, const X86::Instruction&); template void generic_RM32_unsigned_imm8(Op, const X86::Instruction&); - template + template void generic_RM32_reg32(Op, const X86::Instruction&); template void generic_RM8_imm8(Op, const X86::Instruction&); - template + template void generic_RM8_reg8(Op, const X86::Instruction&); - template + template void generic_reg16_RM16(Op, const X86::Instruction&); - template + template void generic_reg32_RM32(Op, const X86::Instruction&); - template + template void generic_reg8_RM8(Op, const X86::Instruction&); template diff --git a/DevTools/UserspaceEmulator/ValueWithShadow.h b/DevTools/UserspaceEmulator/ValueWithShadow.h index a30aa62bb1..a0bb3e1b7c 100644 --- a/DevTools/UserspaceEmulator/ValueWithShadow.h +++ b/DevTools/UserspaceEmulator/ValueWithShadow.h @@ -59,6 +59,16 @@ public: return (m_shadow & 0x01) != 0x01; } + void set_initialized() + { + if constexpr (sizeof(T) == 4) + m_shadow = 0x01010101; + if constexpr (sizeof(T) == 2) + m_shadow = 0x0101; + if constexpr (sizeof(T) == 1) + m_shadow = 0x01; + } + private: T m_value; T m_shadow;