diff options
author | H.J. Lu <hjl.tools@gmail.com> | 2025-08-15 06:18:30 -0700 |
---|---|---|
committer | H.J. Lu <hjl.tools@gmail.com> | 2025-08-18 05:13:57 -0700 |
commit | 4e46c5a14f39342897cfcb7ecb9c0270f30247f4 (patch) | |
tree | 0898957c1ad6ddd58e06c5ef5fb1da224ed3997f | |
parent | 570f4c0c11910d845c35e94764ded54cb1111583 (diff) | |
download | binutils-4e46c5a14f39342897cfcb7ecb9c0270f30247f4.zip binutils-4e46c5a14f39342897cfcb7ecb9c0270f30247f4.tar.gz binutils-4e46c5a14f39342897cfcb7ecb9c0270f30247f4.tar.bz2 |
ld: Issue an error if group nested too deeply
If a linker script has a group nested too deeply by mistake, issue an
error instead of hanging forever without outputting any error message.
PR ld/33265
* ldlang.c (MAX_NESTED_GROUP_DEPTH): New.
(open_input_bfds): Add a pointer argument for the nested group
count. Increment the count before the while loop and decrement
it after the loop. Issue an error if the nested group count >=
MAX_NESTED_GROUP_DEPTH when processing input statement.
(lang_process): Update open_input_bfds calls.
(cmdline_emit_object_only_section): Likewise.
* testsuite/ld-scripts/libpr33265-1.a: New file.
* testsuite/ld-scripts/libpr33265-2.a: Likewise.
* testsuite/ld-scripts/libpr33265-3a.a: Likewise.
* testsuite/ld-scripts/libpr33265-3b.a: Likewise.
* testsuite/ld-scripts/libpr33265-3c.a: Likewise.
* testsuite/ld-scripts/pr33265-1.d: Likewise.
* testsuite/ld-scripts/pr33265-2.d: Likewise.
* testsuite/ld-scripts/pr33265-3.d: Likewise.
* testsuite/ld-scripts/script.exp: Run PR ld/33265 tests.
Signed-off-by: H.J. Lu <hjl.tools@gmail.com>
-rw-r--r-- | ld/ldlang.c | 41 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/libpr33265-1.a | 1 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/libpr33265-2.a | 1 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/libpr33265-3a.a | 1 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/libpr33265-3b.a | 1 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/libpr33265-3c.a | 1 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/pr33265-1.d | 3 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/pr33265-2.d | 3 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/pr33265-3.d | 3 | ||||
-rw-r--r-- | ld/testsuite/ld-scripts/script.exp | 4 |
10 files changed, 50 insertions, 9 deletions
diff --git a/ld/ldlang.c b/ld/ldlang.c index fc7a7d2..2e6d010 100644 --- a/ld/ldlang.c +++ b/ld/ldlang.c @@ -58,6 +58,9 @@ #define TO_ADDR(X) ((X) >> opb_shift) #define TO_SIZE(X) ((X) << opb_shift) +/* The maximum nested group depth. */ +#define MAX_NESTED_GROUP_DEPTH 100 + /* Local variables. */ static struct obstack stat_obstack; static struct obstack map_obstack; @@ -3634,18 +3637,21 @@ static struct bfd_link_hash_entry *plugin_undefs = NULL; static void open_input_bfds (lang_statement_union_type *s, lang_output_section_statement_type *os, - enum open_bfd_mode mode) + enum open_bfd_mode mode, + unsigned int *nested_group_count_p) { for (; s != NULL; s = s->header.next) { switch (s->header.type) { case lang_constructors_statement_enum: - open_input_bfds (constructor_list.head, os, mode); + open_input_bfds (constructor_list.head, os, mode, + nested_group_count_p); break; case lang_output_section_statement_enum: os = &s->output_section_statement; - open_input_bfds (os->children.head, os, mode); + open_input_bfds (os->children.head, os, mode, + nested_group_count_p); break; case lang_wild_statement_enum: /* Maybe we should load the file's symbols. */ @@ -3654,7 +3660,8 @@ open_input_bfds (lang_statement_union_type *s, && !wildcardp (s->wild_statement.filename) && !archive_path (s->wild_statement.filename)) lookup_name (s->wild_statement.filename); - open_input_bfds (s->wild_statement.children.head, os, mode); + open_input_bfds (s->wild_statement.children.head, os, mode, + nested_group_count_p); break; case lang_group_statement_enum: { @@ -3667,6 +3674,8 @@ open_input_bfds (lang_statement_union_type *s, until no new symbols are added to the list of undefined symbols. */ + ++*nested_group_count_p; + do { #if BFD_SUPPORTS_PLUGINS @@ -3674,7 +3683,8 @@ open_input_bfds (lang_statement_union_type *s, #endif undefs = link_info.hash->undefs_tail; open_input_bfds (s->group_statement.children.head, os, - mode | OPEN_BFD_FORCE); + mode | OPEN_BFD_FORCE, + nested_group_count_p); } while (undefs != link_info.hash->undefs_tail #if BFD_SUPPORTS_PLUGINS @@ -3684,6 +3694,8 @@ open_input_bfds (lang_statement_union_type *s, || (plugin_insert != plugin_insert_save && plugin_undefs) #endif ); + + --*nested_group_count_p; } break; case lang_target_statement_enum: @@ -3696,6 +3708,10 @@ open_input_bfds (lang_statement_union_type *s, lang_statement_list_type add; bfd *abfd; + if (*nested_group_count_p >= MAX_NESTED_GROUP_DEPTH) + fatal (_("%P: group nested too deeply in linker script '%s'\n"), + s->input_statement.filename); + s->input_statement.target = current_target; /* If we are being called from within a group, and this @@ -8285,6 +8301,8 @@ lang_os_merge_sort_children (void) void lang_process (void) { + unsigned int nested_group_count = 0; + lang_os_merge_sort_children (); /* Finalize dynamic list. */ @@ -8316,7 +8334,8 @@ lang_process (void) /* Create a bfd for each input file. */ current_target = default_target; lang_statement_iteration++; - open_input_bfds (statement_list.head, NULL, OPEN_BFD_NORMAL); + open_input_bfds (statement_list.head, NULL, OPEN_BFD_NORMAL, + &nested_group_count); /* Now that open_input_bfds has processed assignments and provide statements we can give values to symbolic origin/length now. */ @@ -8351,7 +8370,8 @@ lang_process (void) last_os = ((lang_output_section_statement_type *) ((char *) lang_os_list.tail - offsetof (lang_output_section_statement_type, next))); - open_input_bfds (*added.tail, last_os, OPEN_BFD_NORMAL); + open_input_bfds (*added.tail, last_os, OPEN_BFD_NORMAL, + &nested_group_count); if (plugin_undefs == link_info.hash->undefs_tail) plugin_undefs = NULL; /* Restore the global list pointer now they have all been added. */ @@ -8402,7 +8422,8 @@ lang_process (void) /* Rescan archives in case new undefined symbols have appeared. */ files = file_chain; lang_statement_iteration++; - open_input_bfds (statement_list.head, NULL, OPEN_BFD_RESCAN); + open_input_bfds (statement_list.head, NULL, OPEN_BFD_RESCAN, + &nested_group_count); lang_list_remove_tail (&file_chain, &files); while (files.head != NULL) { @@ -10886,6 +10907,7 @@ cmdline_emit_object_only_section (void) size_t size, off; bfd_byte *contents; struct stat st; + unsigned int nested_group_count = 0; /* Get a temporary object-only file. */ output_filename = make_temp_file (".obj-only.o"); @@ -10922,7 +10944,8 @@ cmdline_emit_object_only_section (void) cmdline_get_object_only_input_files (); /* Open object-only input files. */ - open_input_bfds (statement_list.head, NULL, OPEN_BFD_NORMAL); + open_input_bfds (statement_list.head, NULL, OPEN_BFD_NORMAL, + &nested_group_count); ldemul_after_open (); diff --git a/ld/testsuite/ld-scripts/libpr33265-1.a b/ld/testsuite/ld-scripts/libpr33265-1.a new file mode 100644 index 0000000..eab1008 --- /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 0000000..10f4b91 --- /dev/null +++ b/ld/testsuite/ld-scripts/libpr33265-2.a @@ -0,0 +1 @@ +GROUP ( ./././././/libpr33265-2.a ) diff --git a/ld/testsuite/ld-scripts/libpr33265-3a.a b/ld/testsuite/ld-scripts/libpr33265-3a.a new file mode 100644 index 0000000..bdd4f9a --- /dev/null +++ b/ld/testsuite/ld-scripts/libpr33265-3a.a @@ -0,0 +1 @@ +GROUP ( ./././././/libpr33265-3b.a ) diff --git a/ld/testsuite/ld-scripts/libpr33265-3b.a b/ld/testsuite/ld-scripts/libpr33265-3b.a new file mode 100644 index 0000000..7458328 --- /dev/null +++ b/ld/testsuite/ld-scripts/libpr33265-3b.a @@ -0,0 +1 @@ +GROUP ( ./././././/libpr33265-3c.a ) diff --git a/ld/testsuite/ld-scripts/libpr33265-3c.a b/ld/testsuite/ld-scripts/libpr33265-3c.a new file mode 100644 index 0000000..4583c09 --- /dev/null +++ b/ld/testsuite/ld-scripts/libpr33265-3c.a @@ -0,0 +1 @@ +GROUP ( libpr33265-3a.a ) diff --git a/ld/testsuite/ld-scripts/pr33265-1.d b/ld/testsuite/ld-scripts/pr33265-1.d new file mode 100644 index 0000000..b0df33d --- /dev/null +++ b/ld/testsuite/ld-scripts/pr33265-1.d @@ -0,0 +1,3 @@ +#source: start.s +#ld: -r --whole-archive -lpr33265-1 +#error: .*group nested too deeply.* diff --git a/ld/testsuite/ld-scripts/pr33265-2.d b/ld/testsuite/ld-scripts/pr33265-2.d new file mode 100644 index 0000000..6e9da74 --- /dev/null +++ b/ld/testsuite/ld-scripts/pr33265-2.d @@ -0,0 +1,3 @@ +#source: start.s +#ld: -r --whole-archive -lpr33265-2 +#error: .*group nested too deeply.* diff --git a/ld/testsuite/ld-scripts/pr33265-3.d b/ld/testsuite/ld-scripts/pr33265-3.d new file mode 100644 index 0000000..a2f42fa --- /dev/null +++ b/ld/testsuite/ld-scripts/pr33265-3.d @@ -0,0 +1,3 @@ +#source: start.s +#ld: -r --whole-archive -lpr33265-3a +#error: .*group nested too deeply.* diff --git a/ld/testsuite/ld-scripts/script.exp b/ld/testsuite/ld-scripts/script.exp index 0b37675..40bfe1a 100644 --- a/ld/testsuite/ld-scripts/script.exp +++ b/ld/testsuite/ld-scripts/script.exp @@ -240,4 +240,8 @@ 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" +run_dump_test "pr33265-3" + set LDFLAGS $old_LDFLAGS |