[PATCH] ld: Issue an error for recursively included linker script

H.J. Lu hjl.tools@gmail.com
Thu Aug 14 15:05:56 GMT 2025


When a linker script is included recursively by mistake, issue an error
instead of hang forever without outputting any error message.

	PR ld/33265
	* ldfile.c (opened_scripts): New.
	(ldfile_try_open_bfd): After reading a linker script, clear the
	opened linker script list and free its memory.
	(ldfile_find_command_file): Issue a fatal error when the linker
	script is included recursively.  Add the linker script to the
	linked list of opened linker scripts.
	* testsuite/ld-scripts/libpr33265-1.a: New file.
	* testsuite/ld-scripts/libpr33265-2.a: Likewise.
	* testsuite/ld-scripts/pr33265-1.d: Likewise.
	* testsuite/ld-scripts/pr33265-2.d: Likewise.
	* testsuite/ld-scripts/script.exp: Run PR ld/33265 tests.

Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
---
 ld/ldfile.c                            | 31 ++++++++++++++++++++++++--
 ld/testsuite/ld-scripts/libpr33265-1.a |  1 +
 ld/testsuite/ld-scripts/libpr33265-2.a |  1 +
 ld/testsuite/ld-scripts/pr33265-1.d    |  3 +++
 ld/testsuite/ld-scripts/pr33265-2.d    |  3 +++
 ld/testsuite/ld-scripts/script.exp     |  3 +++
 6 files changed, 40 insertions(+), 2 deletions(-)
 create mode 100644 ld/testsuite/ld-scripts/libpr33265-1.a
 create mode 100644 ld/testsuite/ld-scripts/libpr33265-2.a
 create mode 100644 ld/testsuite/ld-scripts/pr33265-1.d
 create mode 100644 ld/testsuite/ld-scripts/pr33265-2.d

diff --git a/ld/ldfile.c b/ld/ldfile.c
index ce81fdc266f..98408788f45 100644
--- a/ld/ldfile.c
+++ b/ld/ldfile.c
@@ -76,6 +76,11 @@ typedef struct input_remap
 
 static struct input_remap * input_remaps = NULL;
 
+/* The linked list of opened linker scripts in a linker script.  */
+static struct script_name_list *opened_scripts = NULL;
+
+static void ldfile_script_free (struct script_name_list **);
+
 void
 ldfile_add_remap (const char * pattern, const char * renamed)
 {
@@ -475,6 +480,11 @@ ldfile_try_open_bfd (const char *attempt,
 		  ldfile_assumed_script = false;
 		  fclose (yyin);
 		  yyin = NULL;
+
+		  /* After reading a linker script, clear the opened
+		     linker script list and free its memory.  */
+		  ldfile_script_free (&opened_scripts);
+
 		  if (skip)
 		    {
 		      if (command_line.warn_search_mismatch)
@@ -886,11 +896,12 @@ ldfile_find_command_file (const char *name,
   *search_tail_ptr = NULL;
 
  success:
-  /* PR 24576: Catch the case where the user has accidentally included
-     the same linker script twice.  */
   if (stat (filename, &sbuf1) == 0)
     {
       struct stat sbuf2;
+
+      /* PR 24576: Catch the case where the user has accidentally included
+	 the same linker script twice.  */
       for (script = processed_scripts;
 	   script != NULL;
 	   script = script->next)
@@ -899,6 +910,16 @@ ldfile_find_command_file (const char *name,
 	    && SAME_INODE (sbuf1, sbuf2))
 	  fatal (_("%P: error: linker script file '%s (%s)'"
 		   " appears multiple times\n"), filename, script->name);
+
+      /* PR 33265: Catch the case where the user has accidentally included
+	 the linker script recursively.  */
+      for (script = opened_scripts;
+	   script != NULL;
+	   script = script->next)
+	if (stat (script->name, &sbuf2) == 0
+	    && SAME_INODE (sbuf1, sbuf2))
+	  fatal (_("%P: error: linker script '%s (%s)' included recursively\n"),
+		 filename, script->name);
     }
 
   len = strlen (filename);
@@ -908,6 +929,12 @@ ldfile_find_command_file (const char *name,
   memcpy (script->name, filename, len + 1);
   processed_scripts = script;
 
+  script = xmalloc (sizeof (*script) + len);
+  script->next = opened_scripts;
+  script->open_how = open_how;
+  memcpy (script->name, name, len + 1);
+  opened_scripts = script;
+
   free (path);
 
   return result;
diff --git a/ld/testsuite/ld-scripts/libpr33265-1.a b/ld/testsuite/ld-scripts/libpr33265-1.a
new file mode 100644
index 00000000000..eab1008c0a8
--- /dev/null
+++ b/ld/testsuite/ld-scripts/libpr33265-1.a
@@ -0,0 +1 @@
+GROUP ( libpr33265-1.a )
diff --git a/ld/testsuite/ld-scripts/libpr33265-2.a b/ld/testsuite/ld-scripts/libpr33265-2.a
new file mode 100644
index 00000000000..10f4b91aa9e
--- /dev/null
+++ b/ld/testsuite/ld-scripts/libpr33265-2.a
@@ -0,0 +1 @@
+GROUP ( ./././././/libpr33265-2.a )
diff --git a/ld/testsuite/ld-scripts/pr33265-1.d b/ld/testsuite/ld-scripts/pr33265-1.d
new file mode 100644
index 00000000000..1d446a43efb
--- /dev/null
+++ b/ld/testsuite/ld-scripts/pr33265-1.d
@@ -0,0 +1,3 @@
+#source: start.s
+#ld: -r --whole-archive -lpr33265-1
+#error: .*libpr33265-1.a\)' included recursively
diff --git a/ld/testsuite/ld-scripts/pr33265-2.d b/ld/testsuite/ld-scripts/pr33265-2.d
new file mode 100644
index 00000000000..236417eda03
--- /dev/null
+++ b/ld/testsuite/ld-scripts/pr33265-2.d
@@ -0,0 +1,3 @@
+#source: start.s
+#ld: -r --whole-archive -lpr33265-2
+#error: .*libpr33265-2.a\)' included recursively
diff --git a/ld/testsuite/ld-scripts/script.exp b/ld/testsuite/ld-scripts/script.exp
index 0b37675ebe8..5e52179fdbf 100644
--- a/ld/testsuite/ld-scripts/script.exp
+++ b/ld/testsuite/ld-scripts/script.exp
@@ -240,4 +240,7 @@ run_dump_test "segment-start" {{name (default)}}
 run_dump_test "segment-start" {{name (overridden)} \
 			       {ld -Ttext-segment=0x10000000}}
 
+run_dump_test "pr33265-1"
+run_dump_test "pr33265-2"
+
 set LDFLAGS $old_LDFLAGS
-- 
2.50.1



More information about the Binutils mailing list