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.

[env:xiaoblesense]
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\arduino-core-mbed.py 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.