The startup crash in every game, and it was never a dangling pointer.
0xFFFFFFFFFFFFFFFF is not an address. It is what Windows puts in an
access violation record when the fault was a general protection fault,
and the classic way to take one of those is an aligned SSE load on an
address that is not aligned. That is what both traces were:
PaletteKeyEqual calls GSVector4i::compare64, which casts its arguments
to GSVector4i* and indexes them, so both CLUTs have to be 16-byte
aligned.
They were, until I moved the CLUT into the Palette (da4d6052a). The
allocation it replaced was memalign_alloc(64, ...); inside the object
the array landed at offset eight, behind m_alive and m_refs, and every
comparison of two CLUTs faulted. First paletted texture, every game.
alignas(GS_OBJECT_POOL_ALIGN) on the array, and the pool's slots are
aligned to that too: sixty-four, which is the cache line and what the
allocations these pools replaced asked for. The three fallback paths
that go to the allocator when a pool is full ask for the same.
This is also the answer to the earlier heap corruption, and I had it
backwards for three rounds: the free that reported it was a symptom, the
searches for a double free found nothing because there was not one, and
the FastList guard and the erase-before-delete fix - both correct on
their own - fixed things that were not this. A general protection fault
does not look like a bad pointer, and I read the -1 as one.
tests/gsalign: a CLUT inside a pooled object, aligned, compared with an
aligned SSE load, sixty-four objects out of a pool. Built without the
alignas it fails on every object, which is the check that matters.
GSTextureCache.cpp, GSHwHack.cpp, GSRendererHW.cpp,
GSTextureReplacements.cpp and GS.cpp compile with the Makefile's flags;
gsalign, gspool and gshash pass, plain and under ASan/UBSan.