From a992d950480be3aa7287fb2dade7b6e372ba371f Mon Sep 17 00:00:00 2001
From: Nguyen Anh Quynh <aquynh@gmail.com>
Date: Mon, 30 May 2016 00:28:11 +0800
Subject: [PATCH] x86: report unsupported instructions in encodeInstruction().
 this fixes c-crashes/crash-24-x64-not-is16bitmemoperand.c

---
 bindings/nodejs/consts/keystone.js            |  1 +
 bindings/python/keystone/keystone_const.py    |  1 +
 .../lib/keystone/keystone_const.rb            |  1 +
 include/keystone/keystone.h                   |  1 +
 llvm/keystone/ks.cpp                          |  4 ++
 .../X86/MCTargetDesc/X86MCCodeEmitter.cpp     | 40 ++++++++++++++-----
 6 files changed, 39 insertions(+), 9 deletions(-)

diff --git a/bindings/nodejs/consts/keystone.js b/bindings/nodejs/consts/keystone.js
index 3bd3f55..3b9f940 100644
--- a/bindings/nodejs/consts/keystone.js
+++ b/bindings/nodejs/consts/keystone.js
@@ -70,6 +70,7 @@ module.exports.ERR_ASM_ESC_OCTAL = 153
 module.exports.ERR_ASM_ESC_SEQUENCE = 154
 module.exports.ERR_ASM_ESC_STR = 155
 module.exports.ERR_ASM_TOKEN_INVALID = 156
+module.exports.ERR_ASM_INSN_UNSUPPORTED = 157
 module.exports.ERR_ASM_INVALIDOPERAND = 512
 module.exports.ERR_ASM_MISSINGFEATURE = 513
 module.exports.ERR_ASM_MNEMONICFAIL = 514
diff --git a/bindings/python/keystone/keystone_const.py b/bindings/python/keystone/keystone_const.py
index a737859..82d04a6 100644
--- a/bindings/python/keystone/keystone_const.py
+++ b/bindings/python/keystone/keystone_const.py
@@ -70,6 +70,7 @@ KS_ERR_ASM_ESC_OCTAL = 153
 KS_ERR_ASM_ESC_SEQUENCE = 154
 KS_ERR_ASM_ESC_STR = 155
 KS_ERR_ASM_TOKEN_INVALID = 156
+KS_ERR_ASM_INSN_UNSUPPORTED = 157
 KS_ERR_ASM_INVALIDOPERAND = 512
 KS_ERR_ASM_MISSINGFEATURE = 513
 KS_ERR_ASM_MNEMONICFAIL = 514
diff --git a/bindings/ruby/keystone_gem/lib/keystone/keystone_const.rb b/bindings/ruby/keystone_gem/lib/keystone/keystone_const.rb
index 1d45192..19ebc85 100644
--- a/bindings/ruby/keystone_gem/lib/keystone/keystone_const.rb
+++ b/bindings/ruby/keystone_gem/lib/keystone/keystone_const.rb
@@ -72,6 +72,7 @@ module Keystone
 	KS_ERR_ASM_ESC_SEQUENCE = 154
 	KS_ERR_ASM_ESC_STR = 155
 	KS_ERR_ASM_TOKEN_INVALID = 156
+	KS_ERR_ASM_INSN_UNSUPPORTED = 157
 	KS_ERR_ASM_INVALIDOPERAND = 512
 	KS_ERR_ASM_MISSINGFEATURE = 513
 	KS_ERR_ASM_MNEMONICFAIL = 514
diff --git a/include/keystone/keystone.h b/include/keystone/keystone.h
index f9e5aff..1e4f085 100644
--- a/include/keystone/keystone.h
+++ b/include/keystone/keystone.h
@@ -126,6 +126,7 @@ typedef enum ks_err {
     KS_ERR_ASM_ESC_SEQUENCE,         // invalid escape sequence (unrecognized character)
     KS_ERR_ASM_ESC_STR,         // broken escape string
     KS_ERR_ASM_TOKEN_INVALID,   // invalid token
+    KS_ERR_ASM_INSN_UNSUPPORTED,   // this instruction is unsupported in this mode
 
     // generic input assembly errors - architecture specific
     KS_ERR_ASM_INVALIDOPERAND = KS_ERR_ASM_ARCH,
diff --git a/llvm/keystone/ks.cpp b/llvm/keystone/ks.cpp
index 35c7527..b0209a7 100644
--- a/llvm/keystone/ks.cpp
+++ b/llvm/keystone/ks.cpp
@@ -124,6 +124,10 @@ const char *ks_strerror(ks_err code)
             return "Invalid escape string (KS_ERR_ASM_ESC_STR)";
         case KS_ERR_ASM_TOKEN_INVALID:   // invalid token from input assembly
             return "Invalid input token (KS_ERR_ASM_TOKEN_INVALID)";
+        case KS_ERR_ASM_INSN_UNSUPPORTED:
+            return "Instruction is unsupported in this mode (KS_ERR_ASM_INSN_UNSUPPORTED)";
+        case KS_ERR_ASM_DIRECTIVE_UNKNOWN:
+            return "Unknown directive (KS_ERR_ASM_DIRECTIVE_UNKNOWN)";
     }
 }
 
diff --git a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
index 0be48c3..2309c8a 100644
--- a/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
+++ b/llvm/lib/Target/X86/MCTargetDesc/X86MCCodeEmitter.cpp
@@ -1290,14 +1290,26 @@ encodeInstruction(MCInst &MI, raw_ostream &OS,
   } else if (MemoryOperand < 0) {
     need_address_override = false;
   } else if (is64BitMode(STI)) {
-    assert(!Is16BitMemOperand(MI, MemoryOperand, STI));
+    //assert(!Is16BitMemOperand(MI, MemoryOperand, STI));
+    if (Is16BitMemOperand(MI, MemoryOperand, STI)) {
+        KsError = KS_ERR_ASM_INSN_UNSUPPORTED;
+        return;
+    }
     need_address_override = Is32BitMemOperand(MI, MemoryOperand);
   } else if (is32BitMode(STI)) {
-    assert(!Is64BitMemOperand(MI, MemoryOperand));
+    //assert(!Is64BitMemOperand(MI, MemoryOperand));
+    if (Is64BitMemOperand(MI, MemoryOperand)) {
+        KsError = KS_ERR_ASM_INSN_UNSUPPORTED;
+        return;
+    }
     need_address_override = Is16BitMemOperand(MI, MemoryOperand, STI);
   } else {
-    assert(is16BitMode(STI));
-    assert(!Is64BitMemOperand(MI, MemoryOperand));
+    //assert(is16BitMode(STI));
+    //assert(!Is64BitMemOperand(MI, MemoryOperand));
+    if (!is16BitMode(STI) || Is64BitMemOperand(MI, MemoryOperand)) {
+        KsError = KS_ERR_ASM_INSN_UNSUPPORTED;
+        return;
+    }
     need_address_override = !Is16BitMemOperand(MI, MemoryOperand, STI);
   }
 
@@ -1323,10 +1335,16 @@ encodeInstruction(MCInst &MI, raw_ostream &OS,
   case X86II::RawFrmDstSrc: {
     //printf(">> aa\n");
     unsigned siReg = MI.getOperand(1).getReg();
-    assert(((siReg == X86::SI && MI.getOperand(0).getReg() == X86::DI) ||
-            (siReg == X86::ESI && MI.getOperand(0).getReg() == X86::EDI) ||
-            (siReg == X86::RSI && MI.getOperand(0).getReg() == X86::RDI)) &&
-           "SI and DI register sizes do not match");
+    //assert(((siReg == X86::SI && MI.getOperand(0).getReg() == X86::DI) ||
+    //        (siReg == X86::ESI && MI.getOperand(0).getReg() == X86::EDI) ||
+    //        (siReg == X86::RSI && MI.getOperand(0).getReg() == X86::RDI)) &&
+    //       "SI and DI register sizes do not match");
+    if (!(siReg == X86::SI && MI.getOperand(0).getReg() == X86::DI) &&
+            !(siReg == X86::ESI && MI.getOperand(0).getReg() == X86::EDI) &&
+            !(siReg == X86::RSI && MI.getOperand(0).getReg() == X86::RDI)) {
+        KsError = KS_ERR_ASM_INSN_UNSUPPORTED;
+        return;
+    }
     // Emit segment override opcode prefix as needed (not for %ds).
     if (MI.getOperand(2).getReg() != X86::DS)
       EmitSegmentOverridePrefix(CurByte, 2, MI, OS);
@@ -1572,7 +1590,11 @@ encodeInstruction(MCInst &MI, raw_ostream &OS,
         const MCOperand &MIMM = MI.getOperand(CurOp++);
         if (MIMM.isImm()) {
           unsigned Val = MIMM.getImm();
-          assert(Val < 16 && "Immediate operand value out of range");
+          // assert(Val < 16 && "Immediate operand value out of range");
+          if (Val >= 16) {
+              KsError = KS_ERR_ASM_INSN_UNSUPPORTED;
+              return;
+          }
           RegNum |= Val;
         }
       }
-- 
GitLab