Throw crashes Arduino

Hello. I’m setting up exception handling in my C++ project and getting a crash when throwing anything - std::exception or even an integer. I have bulid flags set

build_flags = -fexceptions
build_unflags = -fno-exceptions

This code produces “testException: enter throw clause” but nothing after. The Arduino requires a reset after.

void testException() {
  try {
    Serial.print("testException: enter throw clause\n");
    throw 5;
//        throw std::exception();
    Serial.print("testException: exit throw clause\n");
  catch( std::exception& e)
    Serial.print("testException: in catch std::exception\n");
  catch( ... )
    Serial.print("testException: in catch other\n");

Is there additional configuration that I need to set, or am I doing something wrong?

Seeed Xiao nRF52840 Sense
CLion, PlatformIO
Mac M1 Max
Sonoma 14.0

Please post the entire platformio.ini.

Also this likely won’t work with --specs=nano.specs, as newlib-nano is built without exceptions. That would have to removed from the linker flags to link against the full C library. That in turn would blow up the firmware size so bad, you likely wouldn’t be fit so much application code in it anymore.

That explains it.

Here’s my complete platform.ini.

platform = nordicnrf52
board = xiaoblesense
framework = arduino
monitor_speed = 250000
build_flags = -fexceptions
build_unflags = -fno-exceptions

As a test, you can go find C:\Users\<user>\.platformio\platforms\nordicnrf52\builders\frameworks\arduino\mbed-core\ and find the section

and comment out the "--specs=nano.specs" line with a #.

Careful if there are multiple nordicnrf52@xyz folders.

I tried removing the link flag, expecting a bloated executable, but there was no change. There is only one nord folder.

Hm. Even without removing nano.specs, using the platformio.ini and code above, in the disassembly of the firmware I clearly see the C++ exception functions being called, and they are not empty or directly do a terminate.

Disassembly of section .text:

000271b4 <loop>:
   271b4:	b508      	push	{r3, lr}
   271b6:	4913      	ldr	r1, [pc, #76]	; (27204 <loop+0x50>)
   271b8:	4813      	ldr	r0, [pc, #76]	; (27208 <loop+0x54>)
   271ba:	f001 fd57 	bl	28c6c <_ZN7arduino5Print5printEPKc>
   271be:	2004      	movs	r0, #4
   271c0:	f00c fc66 	bl	33a90 <__cxa_allocate_exception>
   271c4:	2305      	movs	r3, #5
   271c6:	6003      	str	r3, [r0, #0]
   271c8:	2200      	movs	r2, #0
   271ca:	4910      	ldr	r1, [pc, #64]	; (2720c <loop+0x58>)
   271cc:	f00c fe76 	bl	33ebc <__cxa_throw>
   271d0:	2901      	cmp	r1, #1
   271d2:	d109      	bne.n	271e8 <loop+0x34>
   271d4:	f00c fcf3 	bl	33bbe <__cxa_begin_catch>
   271d8:	490d      	ldr	r1, [pc, #52]	; (27210 <loop+0x5c>)
   271da:	480b      	ldr	r0, [pc, #44]	; (27208 <loop+0x54>)
   271dc:	f001 fd46 	bl	28c6c <_ZN7arduino5Print5printEPKc>
   271e0:	e8bd 4008 	ldmia.w	sp!, {r3, lr}
   271e4:	f00c bd15 	b.w	33c12 <__cxa_end_catch>
   271e8:	f00c fce9 	bl	33bbe <__cxa_begin_catch>
   271ec:	4909      	ldr	r1, [pc, #36]	; (27214 <loop+0x60>)
   271ee:	4806      	ldr	r0, [pc, #24]	; (27208 <loop+0x54>)
   271f0:	f001 fd3c 	bl	28c6c <_ZN7arduino5Print5printEPKc>
   271f4:	e7f4      	b.n	271e0 <loop+0x2c>
   271f6:	f00c fd0c 	bl	33c12 <__cxa_end_catch>
   271fa:	f00c fd5a 	bl	33cb2 <__cxa_end_cleanup>
   271fe:	f00c fd08 	bl	33c12 <__cxa_end_catch>
   27202:	e7fa      	b.n	271fa <loop+0x46>
   27204:	000389d8 	.word	0x000389d8
   27208:	20006754 	.word	0x20006754
   2720c:	0003a604 	.word	0x0003a604
   27210:	000389fb 	.word	0x000389fb
   27214:	00038a23 	.word	0x00038a23

00033ebc <__cxa_throw>:
   33ebc:	b508      	push	{r3, lr}
   33ebe:	4604      	mov	r4, r0
   33ec0:	460d      	mov	r5, r1
   33ec2:	4616      	mov	r6, r2
   33ec4:	f7ff fece 	bl	33c64 <__cxa_get_globals>
   33ec8:	6843      	ldr	r3, [r0, #4]
   33eca:	3301      	adds	r3, #1
   33ecc:	6043      	str	r3, [r0, #4]
   33ece:	4632      	mov	r2, r6
   33ed0:	4629      	mov	r1, r5
   33ed2:	4620      	mov	r0, r4
   33ed4:	f7ff ffc6 	bl	33e64 <__cxa_init_primary_exception>
   33ed8:	4604      	mov	r4, r0
   33eda:	2301      	movs	r3, #1
   33edc:	f844 3b28 	str.w	r3, [r4], #40
   33ee0:	4620      	mov	r0, r4
   33ee2:	f001 fcb7 	bl	35854 <_Unwind_RaiseException>
   33ee6:	4620      	mov	r0, r4
   33ee8:	f7ff fe69 	bl	33bbe <__cxa_begin_catch>
   33eec:	f7ff feca 	bl	33c84 <_ZSt9terminatev>

So it’s not like they’re not compiled in at all. Something else must be happening. Something that I could only see with a debugger and instruction-wise stepping. But sadly I don’t even have the board.

That disassembly also matches the source code.

This is all very interesting. Yes, it seems like the mechanisms are there. I appreciate the work to look into this.

I can, of course, work around the lack of exceptions, but if you are will to continue, I am more than happy to drop a device in the mail for you.

I’m definitely not saying no to a free board, but international shipping to Germany would likely be far more expensive than me buying locally. I can get a Seeed Xiao BLE nRF52840 for 14€ + 5€ shipping, or the Sense (has IMU) version for 20€ + 5€ shipping.