Merge pull request #174 from rtissera/chd-alignment-fix

Minimal fix for chd / lzma alignment issues
This commit is contained in:
Autechre 2020-11-01 17:20:18 +01:00 committed by GitHub
commit 9e87be6f57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

137
deps/libchdr/chd.c vendored
View File

@ -214,6 +214,7 @@ typedef struct _zlib_allocator zlib_allocator;
struct _zlib_allocator
{
UINT32 * allocptr[MAX_ZLIB_ALLOCS];
UINT32 * allocptr2[MAX_ZLIB_ALLOCS];
};
typedef struct _zlib_codec_data zlib_codec_data;
@ -233,6 +234,7 @@ struct _lzma_allocator
void (*Free)(void *p, void *address); /* address can be 0 */
void (*FreeSz)(void *p, void *address, size_t size); /* address can be 0 */
uint32_t* allocptr[MAX_LZMA_ALLOCS];
uint32_t* allocptr2[MAX_LZMA_ALLOCS];
};
typedef struct _lzma_codec_data lzma_codec_data;
@ -385,37 +387,41 @@ static chd_error cdfl_codec_init(void* codec, uint32_t hunkbytes);
static void cdfl_codec_free(void* codec);
static chd_error cdfl_codec_decompress(void *codec, const uint8_t *src, uint32_t complen, uint8_t *dest, uint32_t destlen);
//**************************************************************************
// LZMA ALLOCATOR HELPER
//**************************************************************************
/***************************************************************************
* LZMA ALLOCATOR HELPER
***************************************************************************
*/
void *lzma_fast_alloc(void *p, size_t size);
void lzma_fast_free(void *p, void *address);
static void *lzma_fast_alloc(void *p, size_t size);
static void lzma_fast_free(void *p, void *address);
//-------------------------------------------------
// lzma_allocator_init
//-------------------------------------------------
/*-------------------------------------------------
* lzma_allocator_init
*-------------------------------------------------
*/
void lzma_allocator_init(void* p)
static void lzma_allocator_init(void* p)
{
lzma_allocator *codec = (lzma_allocator *)(p);
// reset pointer list
/* reset pointer list */
memset(codec->allocptr, 0, sizeof(codec->allocptr));
memset(codec->allocptr2, 0, sizeof(codec->allocptr2));
codec->Alloc = lzma_fast_alloc;
codec->Free = lzma_fast_free;
}
//-------------------------------------------------
// lzma_allocator_free
//-------------------------------------------------
/*-------------------------------------------------
* lzma_allocator_free
*-------------------------------------------------
*/
void lzma_allocator_free(void* p )
static void lzma_allocator_free(void* p )
{
int i;
int i;
lzma_allocator *codec = (lzma_allocator *)(p);
// free our memory
/* free our memory */
for (i = 0 ; i < MAX_LZMA_ALLOCS ; i++)
{
if (codec->allocptr[i] != NULL)
@ -423,74 +429,91 @@ void lzma_allocator_free(void* p )
}
}
//-------------------------------------------------
// lzma_fast_alloc - fast malloc for lzma, which
// allocates and frees memory frequently
//-------------------------------------------------
/*-------------------------------------------------
* lzma_fast_alloc - fast malloc for lzma, which
* allocates and frees memory frequently
*-------------------------------------------------
*/
void *lzma_fast_alloc(void *p, size_t size)
/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
#define LZMA_MIN_ALIGNMENT_BITS 512
#define LZMA_MIN_ALIGNMENT_BYTES (LZMA_MIN_ALIGNMENT_BITS / 8)
static void *lzma_fast_alloc(void *p, size_t size)
{
int scan;
uint32_t *addr = NULL;
int scan;
uint32_t *addr = NULL;
lzma_allocator *codec = (lzma_allocator *)(p);
uintptr_t vaddr = 0;
// compute the size, rounding to the nearest 1k
/* compute the size, rounding to the nearest 1k */
size = (size + 0x3ff) & ~0x3ff;
// reuse a hunk if we can
/* reuse a hunk if we can */
for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
{
uint32_t *ptr = codec->allocptr[scan];
if (ptr != NULL && size == *ptr)
{
// set the low bit of the size so we don't match next time
/* set the low bit of the size so we don't match next time */
*ptr |= 1;
return ptr + 1;
/* return aligned address of the block */
return codec->allocptr2[scan];
}
}
// alloc a new one and put it into the list
addr = (uint32_t *)malloc(sizeof(uint8_t) * (size + sizeof(uint32_t)));
/* alloc a new one and put it into the list */
addr = (uint32_t *)malloc(size + sizeof(uint32_t) + LZMA_MIN_ALIGNMENT_BYTES);
if (addr==NULL)
return NULL;
for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
{
if (codec->allocptr[scan] == NULL)
{
/* store block address */
codec->allocptr[scan] = addr;
/* compute aligned address, store it */
vaddr = (uintptr_t)addr;
vaddr = (vaddr + sizeof(uint32_t) + (LZMA_MIN_ALIGNMENT_BYTES-1)) & (~(LZMA_MIN_ALIGNMENT_BYTES-1));
codec->allocptr2[scan] = (uint32_t*)vaddr;
break;
}
}
// set the low bit of the size so we don't match next time
/* set the low bit of the size so we don't match next time */
*addr = size | 1;
return addr + 1;
/* return aligned address */
return (void*)vaddr;
}
/*-------------------------------------------------
* lzma_fast_free - fast free for lzma, which
* allocates and frees memory frequently
*-------------------------------------------------
*/
//-------------------------------------------------
// lzma_fast_free - fast free for lzma, which
// allocates and frees memory frequently
//-------------------------------------------------
void lzma_fast_free(void *p, void *address)
static void lzma_fast_free(void *p, void *address)
{
int scan;
uint32_t *ptr;
lzma_allocator *codec;
int scan;
uint32_t *ptr = NULL;
lzma_allocator *codec = NULL;
if (address == NULL)
return;
codec = (lzma_allocator *)(p);
// find the hunk
ptr = (uint32_t *)(address) - 1;
/* find the hunk */
ptr = (uint32_t *)address;
for (scan = 0; scan < MAX_LZMA_ALLOCS; scan++)
{
if (ptr == codec->allocptr[scan])
if (ptr == codec->allocptr2[scan])
{
// clear the low bit of the size to allow matches
*ptr &= ~1;
/* clear the low bit of the size to allow matches */
*codec->allocptr[scan] &= ~1;
return;
}
}
@ -2391,9 +2414,14 @@ static chd_error zlib_codec_decompress(void *codec, const uint8_t *src, uint32_t
allocates and frees memory frequently
-------------------------------------------------*/
/* Huge alignment values for possible SIMD optimization by compiler (NEON, SSE, AVX) */
#define ZLIB_MIN_ALIGNMENT_BITS 512
#define ZLIB_MIN_ALIGNMENT_BYTES (ZLIB_MIN_ALIGNMENT_BITS / 8)
static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
{
zlib_allocator *alloc = (zlib_allocator *)opaque;
uintptr_t paddr = 0;
UINT32 *ptr;
int i;
@ -2408,12 +2436,14 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
{
/* set the low bit of the size so we don't match next time */
*ptr |= 1;
return ptr + 1;
/* return aligned block address */
return (voidpf)(alloc->allocptr2[i]);
}
}
/* alloc a new one */
ptr = (UINT32 *)malloc(size + sizeof(UINT32));
ptr = (UINT32 *)malloc(size + sizeof(UINT32) + ZLIB_MIN_ALIGNMENT_BYTES);
if (!ptr)
return NULL;
@ -2422,14 +2452,17 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
if (!alloc->allocptr[i])
{
alloc->allocptr[i] = ptr;
paddr = (((uintptr_t)ptr) + sizeof(UINT32) + (ZLIB_MIN_ALIGNMENT_BYTES-1)) & (~(ZLIB_MIN_ALIGNMENT_BYTES-1));
alloc->allocptr2[i] = (uint32_t*)paddr;
break;
}
/* set the low bit of the size so we don't match next time */
*ptr = size | 1;
return ptr + 1;
}
/* return aligned block address */
return (voidpf)paddr;
}
/*-------------------------------------------------
zlib_fast_free - fast free for ZLIB, which
@ -2439,15 +2472,15 @@ static voidpf zlib_fast_alloc(voidpf opaque, uInt items, uInt size)
static void zlib_fast_free(voidpf opaque, voidpf address)
{
zlib_allocator *alloc = (zlib_allocator *)opaque;
UINT32 *ptr = (UINT32 *)address - 1;
UINT32 *ptr = (UINT32 *)address;
int i;
/* find the hunk */
for (i = 0; i < MAX_ZLIB_ALLOCS; i++)
if (ptr == alloc->allocptr[i])
if (ptr == alloc->allocptr2[i])
{
/* clear the low bit of the size to allow matches */
*ptr &= ~1;
*(alloc->allocptr[i]) &= ~1;
return;
}
}