Fix tight loop on recursively-defined symbols
authorAlan Modra <amodra@gmail.com>
Fri, 15 May 2020 08:36:05 +0000 (18:06 +0930)
committerAlan Modra <amodra@gmail.com>
Fri, 15 May 2020 08:51:07 +0000 (18:21 +0930)
This patch fixes a bug in GAS where the assembler enters a tight loop
when attempting to resolve recursively-defined symbols, e.g. when
trying to assemble "a=a".

This is a regression introduced between binutils 2.32 and 2.33,
by commit 1903f1385bff9

* symbols.c (struct local_symbol): Update comment.
(resolve_symbol_value): For resolved symbols equated to other
symbols, verify that the referenced symbol is not a local_symbol
before accessing sy_value.  Don't leave symbol loops during
finalize_syms resolution.
* testsuite/gas/all/assign-bad-recursive.d: New test.
* testsuite/gas/all/assign-bad-recursive.l: Error output for test.
* testsuite/gas/all/assign-bad-recursive.s: Assembly for test.
* testsuite/gas/all/gas.exp: Run it.

gas/ChangeLog
gas/symbols.c
gas/testsuite/gas/all/assign-bad-recursive.d [new file with mode: 0644]
gas/testsuite/gas/all/assign-bad-recursive.l [new file with mode: 0644]
gas/testsuite/gas/all/assign-bad-recursive.s [new file with mode: 0644]
gas/testsuite/gas/all/gas.exp

index 3a1f406fd8298675364554a701e052617585c87a..2a987616ecee5dde864bfea08bafc97fecb1cd38 100644 (file)
@@ -1,3 +1,16 @@
+2020-05-15  Alan Modra  <amodra@gmail.com>
+           Alex Coplan  <alex.coplan@arm.com>
+
+       * symbols.c (struct local_symbol): Update comment.
+       (resolve_symbol_value): For resolved symbols equated to other
+       symbols, verify that the referenced symbol is not a local_symbol
+       before accessing sy_value.  Don't leave symbol loops during
+       finalize_syms resolution.
+       * testsuite/gas/all/assign-bad-recursive.d: New test.
+       * testsuite/gas/all/assign-bad-recursive.l: Error output for test.
+       * testsuite/gas/all/assign-bad-recursive.s: Assembly for test.
+       * testsuite/gas/all/gas.exp: Run it.
+
 2020-05-14  Nick Clifton  <nickc@redhat.com>
 
        * po/sv.po: Updated Swedish translation.
index 160b0f74021e92e8858d331a1988b9927a34a0b2..711730daf1c644b4b5647a5a236406bb1aae272f 100644 (file)
@@ -114,7 +114,7 @@ struct symbol
 /* A pointer in the symbol may point to either a complete symbol
    (struct symbol above) or to a local symbol (struct local_symbol
    defined here).  The symbol code can detect the case by examining
-   the first field.  It is always NULL for a local symbol.
+   the first field which is present in both structs.
 
    We do this because we ordinarily only need a small amount of
    information for a local symbol.  The symbol table takes up a lot of
@@ -1237,11 +1237,18 @@ resolve_symbol_value (symbolS *symp)
   if (symp->sy_flags.sy_resolved)
     {
       final_val = 0;
-      while (symp->sy_value.X_op == O_symbol
-            && symp->sy_value.X_add_symbol->sy_flags.sy_resolved)
+      while (symp->sy_value.X_op == O_symbol)
        {
          final_val += symp->sy_value.X_add_number;
          symp = symp->sy_value.X_add_symbol;
+         if (LOCAL_SYMBOL_CHECK (symp))
+           {
+             struct local_symbol *locsym = (struct local_symbol *) symp;
+             final_val += locsym->lsy_value;
+             return final_val;
+           }
+         if (!symp->sy_flags.sy_resolved)
+           return 0;
        }
       if (symp->sy_value.X_op == O_constant)
        final_val += symp->sy_value.X_add_number;
@@ -1380,6 +1387,11 @@ resolve_symbol_value (symbolS *symp)
              break;
            }
 
+         /* Don't leave symbol loops.  */
+         if (finalize_syms
+             && add_symbol->sy_flags.sy_resolving)
+           break;
+
          if (finalize_syms && final_val == 0)
            {
              if (LOCAL_SYMBOL_CHECK (add_symbol))
diff --git a/gas/testsuite/gas/all/assign-bad-recursive.d b/gas/testsuite/gas/all/assign-bad-recursive.d
new file mode 100644 (file)
index 0000000..aeec5d5
--- /dev/null
@@ -0,0 +1,4 @@
+#name: bad recursive assignments
+#source: assign-bad-recursive.s
+#xfail: bfin-*-*
+#error_output: assign-bad-recursive.l
diff --git a/gas/testsuite/gas/all/assign-bad-recursive.l b/gas/testsuite/gas/all/assign-bad-recursive.l
new file mode 100644 (file)
index 0000000..70eaf0f
--- /dev/null
@@ -0,0 +1,7 @@
+[^:]*: Assembler messages:
+.*: Error: symbol definition loop encountered at `aaa'
+#...
+.*: Error: symbol definition loop encountered at `iii'
+#...
+.*: Error: symbol definition loop encountered at `xxx'
+#pass
diff --git a/gas/testsuite/gas/all/assign-bad-recursive.s b/gas/testsuite/gas/all/assign-bad-recursive.s
new file mode 100644 (file)
index 0000000..21917d9
--- /dev/null
@@ -0,0 +1,8 @@
+ aaa = aaa
+
+ iii = jjj
+ jjj = iii
+
+ xxx = yyy
+ yyy = zzz
+ zzz = xxx
index d4140537827965447c3d4808a2380337772a809b..1664018c0f93d613a01d3f8ceef7625320c8a5f3 100644 (file)
@@ -97,6 +97,7 @@ if { ![istarget "bfin-*-*"] } then {
     gas_test "assign-ok.s" "" "" "== assignment support"
 }
 gas_test_error "assign-bad.s" "" "== assignment for symbol already set"
+run_dump_test assign-bad-recursive
 
 run_dump_test simple-forward
 run_dump_test forward