diff options
author | Simon Martin <simon@nasilyan.com> | 2024-11-05 10:16:39 +0100 |
---|---|---|
committer | Simon Martin <simon@nasilyan.com> | 2024-11-05 10:18:00 +0100 |
commit | 5821f5c8c89a054e34cea00e042996dfdcd7e102 (patch) | |
tree | 10e69b706e19e9d344bfb996f7613b545abebb37 | |
parent | b1d92aeb8583c8d1491c97703680c5fb88ed1fe4 (diff) | |
download | gcc-5821f5c8c89a054e34cea00e042996dfdcd7e102.zip gcc-5821f5c8c89a054e34cea00e042996dfdcd7e102.tar.gz gcc-5821f5c8c89a054e34cea00e042996dfdcd7e102.tar.bz2 |
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.
-rw-r--r-- | gcc/cp/init.cc | 5 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/init/new52.C | 14 | ||||
-rw-r--r-- | 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 0527f53..12c673e 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 0000000..5eee213 --- /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 0000000..93d49db --- /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." } |