Skip to content

Interrupt unsafety in XEmacPs_GetQxOffset() #374

@stianke

Description

@stianke

XEmacPs_GetQxOffset(), which is called from XEmacPs_IntrHandler(), contains "u32 Map", a local C-array with an initializer, which is assigned every time the function is called. When my compiler compiles this (gcc + FreeRTOS on Cortex-A9), it uses memcpy to materialize the array on the stack, resulting in memcpy being called from the ISR. Many toolchains provide optimized memcpy implementations that may use FPU registers. In e.g. FreeRTOS Cortex-A ports, the FPU context is generally not preserved for interrupts, which makes memcpy unsafe for use in interrupts (see e.g. https://www.freertos.org/Using-FreeRTOS-on-Cortex-A-Embedded-Processors). So if a task uses memcpy (or any other FPU operation), any memcpy-usage in an ISR could trash the FPU state.
This is likely compiler dependent. Turning the "u32 Map" into a "static const u32 Map" appears to entirely resolve the issue, at least with my compiler, as the array is no longer initialized every time the function is called at runtime, and memcpy is no longer included when looking at the disassembly. This should be safe across compilers, and it also reduces ISR stack usage.

I discovered the bug when I noticed that data I copied with memcpy contained corrupted chunks if I received ethernet interrupts during the tasks memcpy execution. I was able to reliably reproduce this, and confirmed that "static const" for "u32 Map" resolved it.

My disassembly code for XEmacPs_GetQxOffset, which shows that memcpy is being used (9th instruction) is shown below:

00117518 <XEmacPs_GetQxOffset>:
  117518:	e92d4030 	push	{r4, r5, lr}
  11751c:	e1a04001 	mov	r4, r1
  117520:	e24dd064 	sub	sp, sp, #100	@ 0x64
  117524:	e3021780 	movw	r1, #10112	@ 0x2780
  117528:	e1a05000 	mov	r5, r0
  11752c:	e3a02060 	mov	r2, #96	@ 0x60
  117530:	e3401012 	movt	r1, #18
  117534:	e1a0000d 	mov	r0, sp
  117538:	ebffa696 	bl	100f98 <memcpy>
  11753c:	e3540004 	cmp	r4, #4
  117540:	8a000005 	bhi	11755c <XEmacPs_GetQxOffset+0x44>
  117544:	e0844105 	add	r4, r4, r5, lsl #2
  117548:	e28d3060 	add	r3, sp, #96	@ 0x60
  11754c:	e0834104 	add	r4, r3, r4, lsl #2
  117550:	e5140060 	ldr	r0, [r4, #-96]	@ 0xffffffa0
  117554:	e28dd064 	add	sp, sp, #100	@ 0x64
  117558:	e8bd8030 	pop	{r4, r5, pc}
  11755c:	e30336f0 	movw	r3, #14064	@ 0x36f0
  117560:	e3030740 	movw	r0, #14144	@ 0x3740
  117564:	e59f200c 	ldr	r2, [pc, #12]	@ 117578 <XEmacPs_GetQxOffset+0x60>
  117568:	e3403012 	movt	r3, #18
  11756c:	e3a0107f 	mov	r1, #127	@ 0x7f
  117570:	e3400012 	movt	r0, #18
  117574:	fa000172 	blx	117b44 <__assert_func>
  117578:	001227e0 	.word	0x001227e0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions