aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorNathaniel Shead <nathanieloshead@gmail.com>2025-02-10 22:15:30 +1100
committerNathaniel Shead <nathanieloshead@gmail.com>2025-02-11 22:26:52 +1100
commitef83fae50d8f085fe8440bfa595875a2e2329871 (patch)
treecf2c81c3f50f24bf30a0c558e1c3b7eeb40c0441 /gcc
parent7317fc0b03380a83ad03a5fc4fabef5f38c44c9d (diff)
downloadgcc-ef83fae50d8f085fe8440bfa595875a2e2329871.zip
gcc-ef83fae50d8f085fe8440bfa595875a2e2329871.tar.gz
gcc-ef83fae50d8f085fe8440bfa595875a2e2329871.tar.bz2
c++: Fix use-after-free of replaced friend instantiation [PR118807]
When instantiating a friend function, we call register_specialization which adds it to the DECL_TEMPLATE_INSTANTIATIONS of the template. However, in some circumstances we might immediately call pushdecl and find an existing specialisation. In this case, when reregistering the specialisation we also need to update the DECL_TEMPLATE_INSTANTIATIONS list so that we don't try to access the freed spec again later. PR c++/118807 gcc/cp/ChangeLog: * pt.cc (reregister_specialization): Remove spec from DECL_TEMPLATE_INSTANTIATIONS. gcc/testsuite/ChangeLog: * g++.dg/modules/pr118807.C: New test. Signed-off-by: Nathaniel Shead <nathanieloshead@gmail.com> Reviewed-by: Jason Merrill <jason@redhat.com>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/cp/pt.cc11
-rw-r--r--gcc/testsuite/g++.dg/modules/pr118807.C11
2 files changed, 22 insertions, 0 deletions
diff --git a/gcc/cp/pt.cc b/gcc/cp/pt.cc
index 8108bf5..f857b3f 100644
--- a/gcc/cp/pt.cc
+++ b/gcc/cp/pt.cc
@@ -1985,6 +1985,17 @@ reregister_specialization (tree spec, tree tinfo, tree new_spec)
gcc_assert (entry->spec == spec || entry->spec == new_spec);
gcc_assert (new_spec != NULL_TREE);
entry->spec = new_spec;
+
+ /* We need to also remove SPEC from DECL_TEMPLATE_INSTANTIATIONS
+ if it was placed there. */
+ for (tree *inst = &DECL_TEMPLATE_INSTANTIATIONS (elt.tmpl);
+ *inst; inst = &TREE_CHAIN (*inst))
+ if (TREE_VALUE (*inst) == spec)
+ {
+ *inst = TREE_CHAIN (*inst);
+ break;
+ }
+
return 1;
}
diff --git a/gcc/testsuite/g++.dg/modules/pr118807.C b/gcc/testsuite/g++.dg/modules/pr118807.C
new file mode 100644
index 0000000..a97afb9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/modules/pr118807.C
@@ -0,0 +1,11 @@
+// PR c++/118807
+// { dg-additional-options "-fmodules --param=ggc-min-expand=0 --param=ggc-min-heapsize=0 -Wno-global-module" }
+
+module;
+template <typename> class basic_streambuf;
+template <typename> struct basic_streambuf {
+ friend void __istream_extract();
+};
+template class basic_streambuf<char>;
+template class basic_streambuf<wchar_t>;
+export module M;