瀏覽代碼

jar_xm: Workaround for unaligned pointer accesses

jar_xm.h does some shady pointer casts leading to unaligned accesses
and breaking strict aliasing. x86 has special circuitry for doing
unaligned accesses, but on other architectures, it may trap and require
kernel fix-up or crash outright. With this patch, one obstacle in
porting raylib to the GameBoy Advance has been removed. Go for it ;-)

To avoid having to rewrite that `mempool' code, insert padding before
structs and instruct the compiler (GCC, most importantly), to be gentle
when optimizing.

This fixes #490 (Unless we got ourselves 256-bit pointers, if so,
hello future!)
Ahmad Fatoum 7 年之前
父節點
當前提交
1430d01906
共有 3 個文件被更改,包括 16 次插入1 次删除
  1. 2 0
      CMakeLists.txt
  2. 3 1
      src/Makefile
  3. 11 0
      src/external/jar_xm.h

+ 2 - 0
CMakeLists.txt

@@ -29,6 +29,8 @@ endfunction()
 
 add_if_flag_works(-Werror=pointer-arith CMAKE_C_FLAGS)
 add_if_flag_works(-Werror=implicit-function-declaration CMAKE_C_FLAGS)
+# src/external/jar_xm.h does shady stuff
+add_if_flag_works(-fno-strict-aliasing CMAKE_C_FLAGS)
 
 if (ENABLE_ASAN)
     add_if_flag_works(-fno-omit-frame-pointer CMAKE_C_FLAGS CMAKE_LINKER_FLAGS)

+ 3 - 1
src/Makefile

@@ -291,7 +291,9 @@ endif
 #  -Wno-missing-braces   ignore invalid warning (GCC bug 53119)
 #  -D_DEFAULT_SOURCE     use with -std=c99 on Linux and PLATFORM_WEB, required for timespec
 #  -Werror=pointer-arith catch unportable code that does direct arithmetic on void pointers
-CFLAGS += -O1 -Wall -std=c99 -D_DEFAULT_SOURCE -Wno-missing-braces -Werror=pointer-arith
+#  -fno-strict-aliasing  jar_xm.h does shady stuff (breaks strict aliasing)
+CFLAGS += -O1 -Wall -std=c99 -D_DEFAULT_SOURCE -Wno-missing-braces -Werror=pointer-arith 
+-fno-strict-aliasing
 
 ifeq ($(RAYLIB_BUILD_MODE), DEBUG)
     CFLAGS += -g

+ 11 - 0
src/external/jar_xm.h

@@ -612,6 +612,8 @@ int jar_xm_create_context(jar_xm_context_t** ctxp, const char* moddata, uint32_t
     return jar_xm_create_context_safe(ctxp, moddata, SIZE_MAX, rate);
 }
 
+#define ALIGN(x, b) (((x) + ((b) - 1)) & ~((b) - 1))
+#define ALIGN_PTR(x, b) (void*)(((uintptr_t)(x) + ((b) - 1)) & ~((b) - 1))
 int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, size_t moddata_length, uint32_t rate) {
 #if JAR_XM_DEFENSIVE
     int ret;
@@ -644,9 +646,11 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz
 
     ctx->rate = rate;
     mempool = jar_xm_load_module(ctx, moddata, moddata_length, mempool);
+    mempool = ALIGN_PTR(mempool, 16);
 
     ctx->channels = (jar_xm_channel_context_t*)mempool;
     mempool += ctx->module.num_channels * sizeof(jar_xm_channel_context_t);
+    mempool = ALIGN_PTR(mempool, 16);
 
     ctx->global_volume = 1.f;
     ctx->amplification = .25f; /* XXX: some bad modules may still clip. Find out something better. */
@@ -671,6 +675,7 @@ int jar_xm_create_context_safe(jar_xm_context_t** ctxp, const char* moddata, siz
         ch->actual_panning = .5f;
     }
 
+    mempool = ALIGN_PTR(mempool, 16);
     ctx->row_loop_count = (uint8_t*)mempool;
     mempool += MAX_NUM_ROWS * sizeof(uint8_t);
 
@@ -856,9 +861,11 @@ size_t jar_xm_get_memory_needed_for_context(const char* moddata, size_t moddata_
 
     num_patterns = READ_U16(offset + 10);
     memory_needed += num_patterns * sizeof(jar_xm_pattern_t);
+    memory_needed  = ALIGN(memory_needed, 16);
 
     num_instruments = READ_U16(offset + 12);
     memory_needed += num_instruments * sizeof(jar_xm_instrument_t);
+    memory_needed  = ALIGN(memory_needed, 16);
 
     memory_needed += MAX_NUM_ROWS * READ_U16(offset + 4) * sizeof(uint8_t); /* Module length */
 
@@ -875,6 +882,7 @@ size_t jar_xm_get_memory_needed_for_context(const char* moddata, size_t moddata_
         /* Pattern header length + packed pattern data size */
         offset += READ_U32(offset) + READ_U16(offset + 7);
     }
+    memory_needed  = ALIGN(memory_needed, 16);
 
     /* Read instrument headers */
     for(uint16_t i = 0; i < num_instruments; ++i) {
@@ -940,9 +948,11 @@ char* jar_xm_load_module(jar_xm_context_t* ctx, const char* moddata, size_t modd
 
     mod->patterns = (jar_xm_pattern_t*)mempool;
     mempool += mod->num_patterns * sizeof(jar_xm_pattern_t);
+    mempool = ALIGN_PTR(mempool, 16);
 
     mod->instruments = (jar_xm_instrument_t*)mempool;
     mempool += mod->num_instruments * sizeof(jar_xm_instrument_t);
+    mempool = ALIGN_PTR(mempool, 16);
 
     uint16_t flags = READ_U32(offset + 14);
     mod->frequency_type = (flags & (1 << 0)) ? jar_xm_LINEAR_FREQUENCIES : jar_xm_AMIGA_FREQUENCIES;
@@ -1032,6 +1042,7 @@ char* jar_xm_load_module(jar_xm_context_t* ctx, const char* moddata, size_t modd
 
         offset += packed_patterndata_size;
     }
+    mempool = ALIGN_PTR(mempool, 16);
 
     /* Read instruments */
     for(uint16_t i = 0; i < ctx->module.num_instruments; ++i) {