aarch64: Don't assert on long sysreg names
authorAlex Coplan <alex.coplan@arm.com>
Mon, 10 Aug 2020 16:44:02 +0000 (17:44 +0100)
committerAlex Coplan <alex.coplan@arm.com>
Mon, 10 Aug 2020 16:44:02 +0000 (17:44 +0100)
This patch fixes an assertion failure on long system register operands
in the AArch64 backend. See the new testcase for an input which
reproduces the issue.

gas/ChangeLog:

* config/tc-aarch64.c (parse_sys_reg): Don't assert when parsing
a long system register.
(parse_sys_ins_reg): Likewise.
(sysreg_hash_insert): New.
(md_begin): Use sysreg_hash_insert() to ensure all system
registers are no longer than the maximum length at startup.
* testsuite/gas/aarch64/invalid-sysreg-assert.d: New test.
* testsuite/gas/aarch64/invalid-sysreg-assert.l: Error output.
* testsuite/gas/aarch64/invalid-sysreg-assert.s: Input.

include/ChangeLog:

* opcode/aarch64.h (AARCH64_MAX_SYSREG_NAME_LEN): New.

gas/ChangeLog
gas/config/tc-aarch64.c
gas/testsuite/gas/aarch64/invalid-sysreg-assert.d [new file with mode: 0644]
gas/testsuite/gas/aarch64/invalid-sysreg-assert.l [new file with mode: 0644]
gas/testsuite/gas/aarch64/invalid-sysreg-assert.s [new file with mode: 0644]
include/ChangeLog
include/opcode/aarch64.h

index 03628a685d086e4f674fb1ff06616d7cd2739ee6..07def54083e438fa7cca8246be6af2c4fb2f9b99 100644 (file)
@@ -1,3 +1,15 @@
+2020-08-10  Alex Coplan  <alex.coplan@arm.com>
+
+       * config/tc-aarch64.c (parse_sys_reg): Don't assert when parsing
+       a long system register.
+       (parse_sys_ins_reg): Likewise.
+       (sysreg_hash_insert): New.
+       (md_begin): Use sysreg_hash_insert() to ensure all system
+       registers are no longer than the maximum length at startup.
+       * testsuite/gas/aarch64/invalid-sysreg-assert.d: New test.
+       * testsuite/gas/aarch64/invalid-sysreg-assert.l: Error output.
+       * testsuite/gas/aarch64/invalid-sysreg-assert.s: Input.
+
 2020-08-10  Przemyslaw Wirkus  <przemyslaw.wirkus@arm.com>
 
        * config/tc-aarch64.c (parse_sys_reg): Call to
index a46a474af561e7772bb93dc47921371f194e72a4..fdac91ee9d3eb90f2f320936ab149f257d60eaed 100644 (file)
@@ -4100,17 +4100,21 @@ parse_sys_reg (char **str, struct hash_control *sys_regs,
               uint32_t* flags)
 {
   char *p, *q;
-  char buf[32];
+  char buf[AARCH64_MAX_SYSREG_NAME_LEN];
   const aarch64_sys_reg *o;
   int value;
 
   p = buf;
   for (q = *str; ISALNUM (*q) || *q == '_'; q++)
-    if (p < buf + 31)
+    if (p < buf + (sizeof (buf) - 1))
       *p++ = TOLOWER (*q);
   *p = '\0';
-  /* Assert that BUF be large enough.  */
-  gas_assert (p - buf == q - *str);
+
+  /* If the name is longer than AARCH64_MAX_SYSREG_NAME_LEN then it cannot be a
+     valid system register.  This is enforced by construction of the hash
+     table.  */
+  if (p - buf != q - *str)
+    return PARSE_FAIL;
 
   o = hash_find (sys_regs, buf);
   if (!o)
@@ -4161,15 +4165,21 @@ static const aarch64_sys_ins_reg *
 parse_sys_ins_reg (char **str, struct hash_control *sys_ins_regs)
 {
   char *p, *q;
-  char buf[32];
+  char buf[AARCH64_MAX_SYSREG_NAME_LEN];
   const aarch64_sys_ins_reg *o;
 
   p = buf;
   for (q = *str; ISALNUM (*q) || *q == '_'; q++)
-    if (p < buf + 31)
+    if (p < buf + (sizeof (buf) - 1))
       *p++ = TOLOWER (*q);
   *p = '\0';
 
+  /* If the name is longer than AARCH64_MAX_SYSREG_NAME_LEN then it cannot be a
+     valid system register.  This is enforced by construction of the hash
+     table.  */
+  if (p - buf != q - *str)
+    return NULL;
+
   o = hash_find (sys_ins_regs, buf);
   if (!o)
     return NULL;
@@ -8620,6 +8630,13 @@ checked_hash_insert (struct hash_control *table, const char *key, void *value)
     printf ("Internal Error:  Can't hash %s\n", key);
 }
 
+static void
+sysreg_hash_insert (struct hash_control *table, const char *key, void *value)
+{
+  gas_assert (strlen (key) < AARCH64_MAX_SYSREG_NAME_LEN);
+  checked_hash_insert (table, key, value);
+}
+
 static void
 fill_instruction_hash_table (void)
 {
@@ -8694,36 +8711,36 @@ md_begin (void)
   fill_instruction_hash_table ();
 
   for (i = 0; aarch64_sys_regs[i].name != NULL; ++i)
-    checked_hash_insert (aarch64_sys_regs_hsh, aarch64_sys_regs[i].name,
+    sysreg_hash_insert (aarch64_sys_regs_hsh, aarch64_sys_regs[i].name,
                         (void *) (aarch64_sys_regs + i));
 
   for (i = 0; aarch64_pstatefields[i].name != NULL; ++i)
-    checked_hash_insert (aarch64_pstatefield_hsh,
+    sysreg_hash_insert (aarch64_pstatefield_hsh,
                         aarch64_pstatefields[i].name,
                         (void *) (aarch64_pstatefields + i));
 
   for (i = 0; aarch64_sys_regs_ic[i].name != NULL; i++)
-    checked_hash_insert (aarch64_sys_regs_ic_hsh,
+    sysreg_hash_insert (aarch64_sys_regs_ic_hsh,
                         aarch64_sys_regs_ic[i].name,
                         (void *) (aarch64_sys_regs_ic + i));
 
   for (i = 0; aarch64_sys_regs_dc[i].name != NULL; i++)
-    checked_hash_insert (aarch64_sys_regs_dc_hsh,
+    sysreg_hash_insert (aarch64_sys_regs_dc_hsh,
                         aarch64_sys_regs_dc[i].name,
                         (void *) (aarch64_sys_regs_dc + i));
 
   for (i = 0; aarch64_sys_regs_at[i].name != NULL; i++)
-    checked_hash_insert (aarch64_sys_regs_at_hsh,
+    sysreg_hash_insert (aarch64_sys_regs_at_hsh,
                         aarch64_sys_regs_at[i].name,
                         (void *) (aarch64_sys_regs_at + i));
 
   for (i = 0; aarch64_sys_regs_tlbi[i].name != NULL; i++)
-    checked_hash_insert (aarch64_sys_regs_tlbi_hsh,
+    sysreg_hash_insert (aarch64_sys_regs_tlbi_hsh,
                         aarch64_sys_regs_tlbi[i].name,
                         (void *) (aarch64_sys_regs_tlbi + i));
 
   for (i = 0; aarch64_sys_regs_sr[i].name != NULL; i++)
-    checked_hash_insert (aarch64_sys_regs_sr_hsh,
+    sysreg_hash_insert (aarch64_sys_regs_sr_hsh,
                         aarch64_sys_regs_sr[i].name,
                         (void *) (aarch64_sys_regs_sr + i));
 
diff --git a/gas/testsuite/gas/aarch64/invalid-sysreg-assert.d b/gas/testsuite/gas/aarch64/invalid-sysreg-assert.d
new file mode 100644 (file)
index 0000000..a6279bb
--- /dev/null
@@ -0,0 +1,3 @@
+#name: don't assert on long system register
+#source: invalid-sysreg-assert.s
+#error_output: invalid-sysreg-assert.l
diff --git a/gas/testsuite/gas/aarch64/invalid-sysreg-assert.l b/gas/testsuite/gas/aarch64/invalid-sysreg-assert.l
new file mode 100644 (file)
index 0000000..b604910
--- /dev/null
@@ -0,0 +1,2 @@
+[^:]*: Assembler messages:
+.*: Error: unknown or missing system register name at operand 1 -- `msr 00000000000000000000000000000000'
diff --git a/gas/testsuite/gas/aarch64/invalid-sysreg-assert.s b/gas/testsuite/gas/aarch64/invalid-sysreg-assert.s
new file mode 100644 (file)
index 0000000..8b3706f
--- /dev/null
@@ -0,0 +1,2 @@
+// This input caused an assertion failure in parse_sys_reg.
+msr 00000000000000000000000000000000
index 27f14cc111ef4d87a15f445bcb70f7ae67b6d91d..d0475de1ce9f0c0228cb33ada338b29cc6eea3c6 100644 (file)
@@ -1,3 +1,7 @@
+2020-08-10  Alex Coplan  <alex.coplan@arm.com>
+
+       * opcode/aarch64.h (AARCH64_MAX_SYSREG_NAME_LEN): New.
+
 2020-08-10  Przemyslaw Wirkus  <przemyslaw.wirkus@arm.com>
 
        * opcode/aarch64.h (aarch64_sys_reg_deprecated_p): Functions
index 4b71f93b9461bd92692ff9296afa37313b3fd38d..5122ea85658f9f747ca6d6e0dd31fc2005b2d6eb 100644 (file)
@@ -943,6 +943,8 @@ extern const struct aarch64_name_value_pair aarch64_barrier_options [16];
 extern const struct aarch64_name_value_pair aarch64_prfops [32];
 extern const struct aarch64_name_value_pair aarch64_hint_options [];
 
+#define AARCH64_MAX_SYSREG_NAME_LEN 32
+
 typedef struct
 {
   const char *  name;