From 3b7d2f9326eda1a568bb7c4b6014733147b6d7ac Mon Sep 17 00:00:00 2001 From: ejams1 Date: Fri, 2 Oct 2026 18:12:57 -0600 Subject: [PATCH 1/2] Fix BaseExtraList::RemoveExtra leaving _tail inside the removed node _tail points at the last node's next field, so *_tail is always null in a consistent list and the old test (*_tail == iter) never held. Removing the last node left _tail at &removed->next, and the next AddExtra of a non-high-use type wrote through it; re-adding the removed node made it point at itself, and BaseExtraList::RemoveAllDefault then looped or called through a freed object. The test is now _tail == &iter->next, and the removed node's next is cleared so it can be handed back to AddExtra. Co-Authored-By: Claude Opus 5.5 --- include/RE/B/BaseExtraList.h | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/include/RE/B/BaseExtraList.h b/include/RE/B/BaseExtraList.h index 3e4de3796..d00ce12df 100644 --- a/include/RE/B/BaseExtraList.h +++ b/include/RE/B/BaseExtraList.h @@ -65,10 +65,15 @@ namespace RE _head = iter->next; } - if (!_tail || *_tail == iter) { + // _tail points at the last node's `next` field (or at _head when the list is empty), so it + // only moves when the removed node was the last one + if (!_tail || _tail == std::addressof(iter->next)) { _tail = std::addressof(prev ? prev->next : _head); } + // detach the node, so it can be handed back to AddExtra without linking into the list + iter->next = nullptr; + MarkType(a_type, false); return std::unique_ptr{ iter }; } From bdc92c753957412aed9fbeee9edbb8d03538545c Mon Sep 17 00:00:00 2001 From: ejams1 Date: Fri, 2 Oct 2026 18:26:59 -0600 Subject: [PATCH 2/2] Remove the comments from the RemoveExtra fix Co-Authored-By: Claude Opus 5.5 --- include/RE/B/BaseExtraList.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/include/RE/B/BaseExtraList.h b/include/RE/B/BaseExtraList.h index d00ce12df..5c780f327 100644 --- a/include/RE/B/BaseExtraList.h +++ b/include/RE/B/BaseExtraList.h @@ -65,13 +65,10 @@ namespace RE _head = iter->next; } - // _tail points at the last node's `next` field (or at _head when the list is empty), so it - // only moves when the removed node was the last one if (!_tail || _tail == std::addressof(iter->next)) { _tail = std::addressof(prev ? prev->next : _head); } - // detach the node, so it can be handed back to AddExtra without linking into the list iter->next = nullptr; MarkType(a_type, false);