A duplex encoding like 0x00000000 decodes as two loads that both write r0.

Add a check in decode_insns() after both sub-instructions decode
successfully to verify they don't write the same destination register.

Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2696
Signed-off-by: Brian Cain <[email protected]>
Reviewed-by: Pierrick Bouvier <[email protected]>
---
 target/hexagon/decode.c              | 12 ++++++++++++
 tests/tcg/hexagon/invalid-encoding.c | 29 ++++++++++++++++++++++++++++
 2 files changed, 41 insertions(+)

diff --git a/target/hexagon/decode.c b/target/hexagon/decode.c
index 69ba1ec96c..90499fc320 100644
--- a/target/hexagon/decode.c
+++ b/target/hexagon/decode.c
@@ -501,12 +501,24 @@ decode_insns(DisasContext *ctx, Insn *insn, uint32_t 
encoding)
 
         /* The slot1 subinsn needs to be in the packet first */
         if (decode_slot1_subinsn(ctx, slot1_subinsn)) {
+            Insn *slot1_insn = insn;
             insn->generate = opcode_genptr[insn->opcode];
             insn->iclass = iclass_bits(encoding);
             ctx->insn = ++insn;
             if (decode_slot0_subinsn(ctx, slot0_subinsn)) {
                 insn->generate = opcode_genptr[insn->opcode];
                 insn->iclass = iclass_bits(encoding);
+                /*
+                 * Check that the two sub-instructions don't write the same
+                 * destination register (e.g., encoding 0x0 decodes as two
+                 * loads both writing R0, which is an invalid packet).
+                 */
+                if (insn->dest_idx >= 0 && slot1_insn->dest_idx >= 0 &&
+                    insn->regno[insn->dest_idx] ==
+                        slot1_insn->regno[slot1_insn->dest_idx]) {
+                    ctx->insn = --insn;
+                    return 0;
+                }
                 return 2;
             }
             /*
diff --git a/tests/tcg/hexagon/invalid-encoding.c 
b/tests/tcg/hexagon/invalid-encoding.c
index 010a5eb741..1bbd312b61 100644
--- a/tests/tcg/hexagon/invalid-encoding.c
+++ b/tests/tcg/hexagon/invalid-encoding.c
@@ -65,6 +65,34 @@ static int test_invalid_duplex(void)
     return sig;
 }
 
+/*
+ * Duplex with duplicate destination registers (issue #2696):
+ * The encoding 0x00000000 decodes as a duplex with parse bits
+ * [15:14] = 0b00:
+ *   slot1: SL1_loadri_io R0 = memw(R0+#0x0)
+ *   slot0: SL1_loadri_io R0 = memw(R0+#0x0)
+ *
+ * Both sub-instructions write R0, which is an invalid packet (duplicate
+ * destination register).  This should raise SIGILL.
+ */
+static int test_invalid_dups(void)
+{
+    int sig;
+
+    asm volatile(
+        "r0 = #0\n"
+        "r1 = ##1f\n"
+        "memw(%1) = r1\n"
+        ".word 0x00000000\n"
+        "1:\n"
+        "%0 = r0\n"
+        : "=r"(sig)
+        : "r"(&resume_pc)
+        : "r0", "r1", "memory");
+
+    return sig;
+}
+
 int main()
 {
     struct sigaction act;
@@ -75,6 +103,7 @@ int main()
     assert(sigaction(SIGILL, &act, NULL) == 0);
 
     assert(test_invalid_duplex() == SIGILL);
+    assert(test_invalid_dups() == SIGILL);
 
     puts("PASS");
     return EXIT_SUCCESS;
-- 
2.34.1

Reply via email to