From 7d96733b63ac5a9a0b2056ae680dfd21d3d91578 Mon Sep 17 00:00:00 2001 From: Eugene Zaikonnikov Date: Tue, 23 Jun 2026 14:48:18 +0200 Subject: [PATCH 1/2] fix a race supposedly causing #520 and #428 --- lisp-kernel/arm-exceptions.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lisp-kernel/arm-exceptions.c b/lisp-kernel/arm-exceptions.c index ce5f3f2c5..8383fe47b 100644 --- a/lisp-kernel/arm-exceptions.c +++ b/lisp-kernel/arm-exceptions.c @@ -1752,6 +1752,24 @@ pc_luser_xp(ExceptionInformation *xp, TCR *tcr, signed_natural *alloc_disp) return; } + if (allocptr_tag == tag_fixnum) { + /* + * If a thread is suspended just before the instruction that adjusts + * allocptr, the valid allocptr value is still untagged. Normalizing the + * thread for GC will replace allocptr with VOID_ALLOCPTR; leave the PC at + * the allocation start so the resumed thread takes the normal allocation + * trap and receives a fresh segment. + */ + if (IS_SUB_RM_FROM_ALLOCPTR(instr) || + IS_SUB_LO_FROM_ALLOCPTR(instr) || + IS_SUB_FROM_ALLOCPTR(instr)) { + if (!alloc_disp) { + update_bytes_allocated(tcr, (void *)ptr_from_lispobj(cur_allocptr)); + xpGPR(xp, allocptr) = VOID_ALLOCPTR; + } + return; + } + } if (allocptr_tag != tag_fixnum) { From ad5aa17e3903f0e88c8a3f31116823d65738fd74 Mon Sep 17 00:00:00 2001 From: Eugene Zaikonnikov Date: Tue, 23 Jun 2026 15:47:27 +0200 Subject: [PATCH 2/2] change to broader fix --- lisp-kernel/arm-exceptions.c | 105 +++++++++++++++++++++++++++++------ 1 file changed, 88 insertions(+), 17 deletions(-) diff --git a/lisp-kernel/arm-exceptions.c b/lisp-kernel/arm-exceptions.c index 8383fe47b..6e49a4f2b 100644 --- a/lisp-kernel/arm-exceptions.c +++ b/lisp-kernel/arm-exceptions.c @@ -1671,6 +1671,92 @@ restart_allocation(ExceptionInformation *xp) } } +natural +allocptr_adjustment_amount(ExceptionInformation *xp, opcode instr) +{ + if (IS_SUB_RM_FROM_ALLOCPTR(instr)) { + return xpGPR(xp, RM_field(instr)); + } + + if (IS_SUB_LO_FROM_ALLOCPTR(instr)) { + return instr & 0xff; + } + + if (IS_SUB_FROM_ALLOCPTR(instr)) { + return ror(instr & 0xff, (instr & 0xf00) >> 7); + } + + return 0; +} + +Boolean +normalize_allocation_to_trap(ExceptionInformation *xp, TCR *tcr) +{ + pc current = xpPC(xp), start = NULL, trap = NULL, p; + LispObj cur_allocptr = xpGPR(xp, allocptr), original_allocptr, adjusted_allocptr; + natural already_adjusted = 0, total_adjustment = 0, adjustment; + int i; + + for (i = 0; i < 6; i++) { + p = current - i; + if (allocptr_adjustment_amount(xp, *p)) { + start = p; + while ((start > (current - 6)) && + allocptr_adjustment_amount(xp, start[-1])) { + start--; + } + break; + } + } + + if (!start) { + return false; + } + + for (i = 0, p = start; i < 8; i++, p++) { + opcode instr = *p; + + adjustment = allocptr_adjustment_amount(xp, instr); + if (adjustment) { + total_adjustment += adjustment; + if (p < current) { + already_adjusted += adjustment; + } + continue; + } + + if (IS_LOAD_RD_FROM_ALLOCBASE(instr) || + IS_COMPARE_ALLOCPTR_TO_RM(instr) || + IS_BRANCH_AROUND_ALLOC_TRAP(instr)) { + continue; + } + + if (IS_ALLOC_TRAP(instr)) { + trap = p; + break; + } + + return false; + } + + if ((!trap) || (current > trap)) { + return false; + } + + original_allocptr = cur_allocptr + already_adjusted; + adjusted_allocptr = original_allocptr - total_adjustment; + + if ((fulltag_of(original_allocptr) != tag_fixnum) || + (fulltag_of(adjusted_allocptr) == tag_fixnum)) { + return false; + } + + update_bytes_allocated(tcr, (void *)ptr_from_lispobj(original_allocptr)); + xpGPR(xp, allocptr) = adjusted_allocptr; + xpPC(xp) = trap; + return true; +} + void pc_luser_xp(ExceptionInformation *xp, TCR *tcr, signed_natural *alloc_disp) @@ -1752,23 +1838,8 @@ pc_luser_xp(ExceptionInformation *xp, TCR *tcr, signed_natural *alloc_disp) return; } - if (allocptr_tag == tag_fixnum) { - /* - * If a thread is suspended just before the instruction that adjusts - * allocptr, the valid allocptr value is still untagged. Normalizing the - * thread for GC will replace allocptr with VOID_ALLOCPTR; leave the PC at - * the allocation start so the resumed thread takes the normal allocation - * trap and receives a fresh segment. - */ - if (IS_SUB_RM_FROM_ALLOCPTR(instr) || - IS_SUB_LO_FROM_ALLOCPTR(instr) || - IS_SUB_FROM_ALLOCPTR(instr)) { - if (!alloc_disp) { - update_bytes_allocated(tcr, (void *)ptr_from_lispobj(cur_allocptr)); - xpGPR(xp, allocptr) = VOID_ALLOCPTR; - } - return; - } + if ((!alloc_disp) && normalize_allocation_to_trap(xp, tcr)) { + return; }