https://gcc.gnu.org/g:5821f5c8c89a054e34cea00e042996dfdcd7e102

commit r15-4958-g5821f5c8c89a054e34cea00e042996dfdcd7e102
Author: Simon Martin <si...@nasilyan.com>
Date:   Tue Nov 5 10:16:39 2024 +0100

    c++: Don't crash upon invalid placement new operator [PR117101]
    
    We currently crash upon the following invalid code (notice the "void
    void**" parameter)
    
    === cut here ===
    using size_t = decltype(sizeof(int));
    void *operator new(size_t, void void **p) noexcept { return p; }
    int x;
    void f() {
        int y;
        new (&y) int(x);
    }
    === cut here ===
    
    The problem is that in this case, we end up with a NULL_TREE parameter
    list for the new operator because of the error, and (1) coerce_new_type
    wrongly complains about the first parameter type not being size_t,
    (2) std_placement_new_fn_p blindly accesses the parameter list, hence a
    crash.
    
    This patch does NOT address #1 since we can't easily distinguish between
    a new operator declaration without parameters from one with erroneous
    parameters (and it's not worth the risk to refactor and break things for
    an error recovery issue) hence a dg-bogus in new52.C, but it does
    address #2 and the ICE by simply checking the first parameter against
    NULL_TREE.
    
    It also adds a new testcase checking that we complain about new
    operators with no or invalid first parameters, since we did not have
    any.
    
            PR c++/117101
    
    gcc/cp/ChangeLog:
    
            * init.cc (std_placement_new_fn_p): Check first_arg against
            NULL_TREE.
    
    gcc/testsuite/ChangeLog:
    
            * g++.dg/init/new52.C: New test.
            * g++.dg/init/new53.C: New test.

Diff:
---
 gcc/cp/init.cc                    |  5 +++--
 gcc/testsuite/g++.dg/init/new52.C | 14 ++++++++++++++
 gcc/testsuite/g++.dg/init/new53.C |  8 ++++++++
 3 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/gcc/cp/init.cc b/gcc/cp/init.cc
index 0527f53550db..12c673efb2ac 100644
--- a/gcc/cp/init.cc
+++ b/gcc/cp/init.cc
@@ -2980,8 +2980,9 @@ std_placement_new_fn_p (tree alloc_fn)
   if (DECL_NAMESPACE_SCOPE_P (alloc_fn))
     {
       tree first_arg = TREE_CHAIN (TYPE_ARG_TYPES (TREE_TYPE (alloc_fn)));
-      if ((TREE_VALUE (first_arg) == ptr_type_node)
-         && TREE_CHAIN (first_arg) == void_list_node)
+      if (first_arg
+         && (TREE_VALUE (first_arg) == ptr_type_node)
+         && (TREE_CHAIN (first_arg) == void_list_node))
        return true;
     }
   return false;
diff --git a/gcc/testsuite/g++.dg/init/new52.C 
b/gcc/testsuite/g++.dg/init/new52.C
new file mode 100644
index 000000000000..5eee2135724d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/new52.C
@@ -0,0 +1,14 @@
+// PR c++/117101
+// { dg-do "compile" { target c++11 } }
+
+using size_t = decltype(sizeof(int));
+void* operator new(size_t, // { dg-bogus "first parameter" "" { xfail *-*-* } }
+                  void void **p) noexcept // { dg-error "two or more" }
+{
+  return p; // { dg-error "not declared" }
+}
+int x;
+void f() {
+    int y;
+    new (&y) int(x);
+}
diff --git a/gcc/testsuite/g++.dg/init/new53.C 
b/gcc/testsuite/g++.dg/init/new53.C
new file mode 100644
index 000000000000..93d49dbd6c1f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/init/new53.C
@@ -0,0 +1,8 @@
+// Check that we reject operator new with no argument or non-size_t first
+// argument.
+// { dg-do "compile" }
+
+void* operator new(); // { dg-error "takes type .size_t." }
+void* operator new(char); // { dg-error "takes type .size_t." }
+void* operator new(char*); // { dg-error "takes type .size_t." }
+void* operator new(char&); // { dg-error "takes type .size_t." }

Reply via email to