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

H.J. Lu hjl.tools@gmail.com
Sun Aug 10 13:24:09 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_script_list): New.
	(opened_scripts): Likewise.
	(ldfile_opened_script_list_free): Likewise.
	(ldfile_try_open_bfd): After reading a linker script, clear the
	opened linker script list and free its memory.
	(ldfile_open_command_file_1): 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.a: New file.
	* testsuite/ld-scripts/pr33265.d: Likewise.
	* testsuite/ld-scripts/script.exp: Run pr33265.

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

diff --git a/ld/ldfile.c b/ld/ldfile.c
index e642c7f6620..c4619c16f3f 100644
--- a/ld/ldfile.c
+++ b/ld/ldfile.c
@@ -75,6 +75,28 @@ typedef struct input_remap
 
 static struct input_remap * input_remaps = NULL;
 
+struct opened_script_list
+{
+  struct opened_script_list *next;
+  const char *name;
+};
+
+/* The linked list of opened linker scripts in a linker script.  */
+static struct opened_script_list *opened_scripts = NULL;
+
+/* Clear the opened linker script list and free its memory.  */
+
+static void
+ldfile_opened_script_list_free (struct opened_script_list **root)
+{
+  struct opened_script_list *ent;
+  while ((ent = *root) != NULL)
+    {
+      *root = ent->next;
+      free (ent);
+    }
+}
+
 void
 ldfile_add_remap (const char * pattern, const char * renamed)
 {
@@ -474,6 +496,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_opened_script_list_free (&opened_scripts);
+
 		  if (skip)
 		    {
 		      if (command_line.warn_search_mismatch)
@@ -887,6 +914,7 @@ ldfile_open_command_file_1 (const char *name, enum script_open_style open_how)
   FILE *ldlex_input_stack;
   bool sysrooted;
   struct script_name_list *script;
+  struct opened_script_list *opened_script;
   size_t len;
 
   /* PR 24576: Catch the case where the user has accidentally included
@@ -924,6 +952,23 @@ ldfile_open_command_file_1 (const char *name, enum script_open_style open_how)
   lineno = 1;
 
   saved_script_handle = ldlex_input_stack;
+
+  /* PR 33265: Catch the case where the user has accidentally included
+     the linker script recursively.  */
+  for (opened_script = opened_scripts;
+       opened_script != NULL;
+       opened_script = opened_script->next)
+    if (strcmp (name, opened_script->name) == 0)
+      fatal (_("%P: error: linker script '%s' included recursively\n"),
+	     name);
+
+  opened_script = xmalloc (sizeof (*opened_script));
+  /* Since ldfile_opened_script_list_free is called immediately after
+     the linker linker script is processed, only the pointer to string
+     is recorded.  */
+  opened_script->name = name;
+  opened_script->next = opened_scripts;
+  opened_scripts = opened_script;
 }
 
 static void
diff --git a/ld/testsuite/ld-scripts/libpr33265.a b/ld/testsuite/ld-scripts/libpr33265.a
new file mode 100644
index 00000000000..c580ba6c713
--- /dev/null
+++ b/ld/testsuite/ld-scripts/libpr33265.a
@@ -0,0 +1 @@
+GROUP ( libpr33265.a )
diff --git a/ld/testsuite/ld-scripts/pr33265.d b/ld/testsuite/ld-scripts/pr33265.d
new file mode 100644
index 00000000000..761ba3bb1f3
--- /dev/null
+++ b/ld/testsuite/ld-scripts/pr33265.d
@@ -0,0 +1,3 @@
+#source: start.s
+#ld: -r --whole-archive -lpr33265
+#error: .*libpr33265.a' included recursively
diff --git a/ld/testsuite/ld-scripts/script.exp b/ld/testsuite/ld-scripts/script.exp
index 5206563f250..e5f4e1bf117 100644
--- a/ld/testsuite/ld-scripts/script.exp
+++ b/ld/testsuite/ld-scripts/script.exp
@@ -238,4 +238,6 @@ run_dump_test "segment-start" {{name (default)}}
 run_dump_test "segment-start" {{name (overridden)} \
 			       {ld -Ttext-segment=0x10000000}}
 
+run_dump_test "pr33265"
+
 set LDFLAGS $old_LDFLAGS
-- 
2.50.1



More information about the Binutils mailing list