From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id 9A5053858297; Fri, 29 Jul 2022 16:18:22 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 9A5053858297 From: "matthijs at stdin dot nl" To: gcc-bugs@gcc.gnu.org Subject: [Bug libstdc++/106477] New: With -fno-exception operator new(nothrow) aborts instead of returning null Date: Fri, 29 Jul 2022 16:18:22 +0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: new X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: libstdc++ X-Bugzilla-Version: 11.2.1 X-Bugzilla-Keywords: X-Bugzilla-Severity: normal X-Bugzilla-Who: matthijs at stdin dot nl X-Bugzilla-Status: UNCONFIRMED X-Bugzilla-Resolution: X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: unassigned at gcc dot gnu.org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: bug_id short_desc product version bug_status bug_severity priority component assigned_to reporter target_milestone Message-ID: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 X-BeenThere: gcc-bugs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-bugs mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Fri, 29 Jul 2022 16:18:22 -0000 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D106477 Bug ID: 106477 Summary: With -fno-exception operator new(nothrow) aborts instead of returning null Product: gcc Version: 11.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: libstdc++ Assignee: unassigned at gcc dot gnu.org Reporter: matthijs at stdin dot nl Target Milestone: --- The nothrow version of operator new is intended to return null on allocation failure. However, when libstdc++ is compiled with -fno-exceptions, it aborts instead. The cause of this failure is that the nothrow operators work by calling the regular operators, catching any allocation failure exception and turning th= at into a null return. However, with -fno-exceptions, the regular operator abo= rts instead of throwing, so the nothrow operator never gets a chance to return null. Originally, this *did* work as expected, because the nothrow operators would just call malloc directly. However, as reported in https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D68210 this violates the C++11 requirement that the nothrow versions must call the regular versions (so applications can replace the regular version and get the nothrow for free),= so this was changed in https://gcc.gnu.org/git/?p=3Dgcc.git;a=3Dcommitdiff;h=3Db66e5a95c0065fda356= 9a1bfd3766963a848a00d Note this comment by Jonathan Wakely in the linked report, which actually already warns against introducing the behavior I am describing (but the com= ment was apparently not considered when applying the fix): https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D68210#c2 In any case, we have two conflicting requirements: 1. nothrow operators should return null on failure 2. nothrow operators should call regular operators I can see no way to satisfy both. Since -fno-exceptions is already violating the spec, it would make sense to me to, when -fno-exceptions is specified, = only satisfy 1 and allow 2 to be violated (which is more of a fringe case anyway, and applications can always replace the nothrow versions too to get the behavior they need). Essentially this would mean that with -fno-exceptions, the nothrow versions would have to call malloc again directly like before (either duplicating co= de like before, or maybe introducing a null-returning helper function?). To reproduce, I made a small testcase. I was originally seeing this in the Arduino environment on an Atmel samd chip, but I made a self-contained test= case and tested that using gcc from https://developer.arm.com (using the linker script from Atmel/Arduino), which is compiled with -fno-exceptions. The main testcase is simple: An _sbrk() implementation that always fails to force allocation failure (overriding the default libnosys implementation th= at always succeeds), and a single call to operator new that should return null, but aborts: $ cat test.cpp=20 #include volatile void* foo; extern "C" void *_sbrk(int n) { // Just always fail allocation return (void*)-1; } int main() { // This should return nullptr, but actually aborts (with -fno-exceptions) foo =3D new (std::nothrow) char[65000]; return 0; } In addition, I added a minimal startup.c for memory initialization and reset vector and a linker script taken verbatim from https://github.com/arduino/ArduinoCore-samd/raw/master/variants/arduino_zer= o/linker_scripts/gcc/flash_without_bootloader.ld (I will attach both files next). Compiled using: $ ~/Downloads/gcc-arm-11.2-2022.02-x86_64-arm-none-eabi/bin/arm-none-eabi-g= cc -mcpu=3Dcortex-m0plus -mthumb -g -fno-exceptions --specs=3Dnosys.specs --specs=3Dnano.specs -Tflash_without_bootloader.ld -nostartfiles test.cpp startup.c -lstdc++ Running this on the Arduino zero (using openocd and gdb to upload the code through the EDBG port) shows it aborts: Program received signal SIGINT, Interrupt. _exit (rc=3Drc@entry=3D1) at /data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/libgloss/lib= nosys/_exit.c:16 16=20=20=20=20=20 /data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/libgloss/lib= nosys/_exit.c: No such file or directory. (gdb) bt #0 _exit (rc=3Drc@entry=3D1) at /data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/libgloss/lib= nosys/_exit.c:16 #1 0x0000013a in abort () at /data/jenkins/workspace/GNU-toolchain/arm-11/src/newlib-cygwin/newlib/libc/= stdlib/abort.c:59 #2 0x00000128 in operator new (sz=3D65000) at /data/jenkins/workspace/GNU-toolchain/arm-11/src/gcc/libstdc++-v3/libsupc++= /new_op.cc:54 #3 0x00000106 in operator new[] (sz=3D) at /data/jenkins/workspace/GNU-toolchain/arm-11/src/gcc/libstdc++-v3/libsupc++= /new_opv.cc:32 #4 0x000000fe in operator new[] (sz=3D) at /data/jenkins/workspace/GNU-toolchain/arm-11/src/gcc/libstdc++-v3/libsupc++= /new_opvnt.cc:38 #5 0x00000034 in main () at test.cpp:17=