diff --git a/CMakeLists.txt b/CMakeLists.txt index a40eadd..23350d5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -10,21 +10,33 @@ ADD_DEFINITIONS(-D${name}=0) ENDIF() ENDFUNCTION() -OPTION_AND_DEFINE(XM_DEBUG "Enable debugging messages" "ON") -OPTION_AND_DEFINE(XM_BIG_ENDIAN "Assume big endian byte order (default: little endian assumed)" "OFF") +OPTION_AND_DEFINE(XM_DEBUG "Enable debug symbols and print debugging messages to stderr" "ON") +OPTION_AND_DEFINE(XM_DEFENSIVE "Defensively check XM data for errors/inconsistencies" "ON") +OPTION_AND_DEFINE(XM_BIG_ENDIAN "Use big endian byte order (unfinished)" "OFF") OPTION_AND_DEFINE(XM_LINEAR_INTERPOLATION "Use linear interpolation (CPU hungry)" "ON") OPTION_AND_DEFINE(XM_RAMPING "Enable ramping (smooth volume/panning transitions, CPU hungry)" "ON") OPTION(XM_BUILD_SHARED_LIBS "Build shared library" "ON") OPTION(XM_BUILD_EXAMPLES "Build example programs" "ON") +OPTION(XM_DEMO_MODE "Optimize for size (then link statically against libxms and strip dead code)" "OFF") -ADD_DEFINITIONS("-g -Os -Wall -pedantic --std=c11") +ADD_DEFINITIONS("-Wall -pedantic --std=c11") + +IF(XM_DEBUG) +ADD_DEFINITIONS("-g") +ENDIF() + +IF(XM_DEMO_MODE) +ADD_DEFINITIONS("-Os") ADD_DEFINITIONS("-fdata-sections -ffunction-sections") IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin") SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -dead_strip") ELSE() SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") ENDIF() +ELSE() +ADD_DEFINITIONS("-O2") +ENDIF() LIST(APPEND XM_INCLUDE_DIRS "${libxm_SOURCE_DIR}/include") LIST(APPEND XM_LIBRARIES "m") @@ -34,4 +46,3 @@ ADD_SUBDIRECTORY(src) IF(XM_BUILD_EXAMPLES) ADD_SUBDIRECTORY(examples) ENDIF() - diff --git a/Makefile b/Makefile index 6f2181a..09c0b40 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,11 @@ +build-debug: build + @cd build && cmake -D XM_DEBUG=ON -D XM_DEFENSIVE=ON .. + +build-demo: build + @cd build && cmake -D XM_DEBUG=OFF -D XM_DEFENSIVE=OFF -D XM_DEMO_MODE=ON .. + build: @mkdir -p build - @cd build && cmake .. dist-clean: @rm -Rf build diff --git a/src/context.c b/src/context.c index aa0c00b..38aa619 100644 --- a/src/context.c +++ b/src/context.c @@ -18,10 +18,12 @@ int xm_create_context_safe(xm_context_t** ctxp, const char* moddata, size_t modd char* mempool; xm_context_t* ctx; - if((ret = xm_check_header_sanity(moddata, moddata_length))) { - DEBUG("xm_check_header_sanity() returned %i", ret); +#if XM_DEFENSIVE + if((ret = xm_check_sanity_preload(moddata, moddata_length))) { + DEBUG("xm_check_sanity_preload() returned %i, module is not safe to load", ret); return 1; } +#endif bytes_needed = xm_get_memory_needed_for_context(moddata, moddata_length); mempool = malloc(bytes_needed); @@ -67,6 +69,14 @@ int xm_create_context_safe(xm_context_t** ctxp, const char* moddata, size_t modd ctx->row_loop_count = (uint8_t*)mempool; mempool += MAX_NUM_ROWS * sizeof(uint8_t); +#if XM_DEFENSIVE + if((ret = xm_check_sanity_postload(ctx))) { + DEBUG("xm_check_sanity_postload() returned %i, module is not safe to play", ret); + xm_free_context(ctx); + return 1; + } +#endif + return 0; } diff --git a/src/load.c b/src/load.c index a5be93e..cc75a43 100644 --- a/src/load.c +++ b/src/load.c @@ -33,7 +33,9 @@ static inline void memcpy_pad(void* dst, size_t dst_len, const void* src, size_t memset(dst_c + copy_bytes, 0, dst_len - copy_bytes); } -int xm_check_header_sanity(const char* module, size_t module_length) { +#if XM_DEFENSIVE + +int xm_check_sanity_preload(const char* module, size_t module_length) { if(module_length < 60) { return 4; } @@ -54,6 +56,24 @@ int xm_check_header_sanity(const char* module, size_t module_length) { return 0; } +int xm_check_sanity_postload(xm_context_t* ctx) { + /* @todo: plenty of stuff to do hereā€¦ */ + + /* Check the POT */ + for(uint8_t i = 0; i < ctx->module.length; ++i) { + if(ctx->module.pattern_table[i] >= ctx->module.num_patterns) { + DEBUG("module has invalid POT, pos %i references nonexistent pattern %i", + i, + ctx->module.pattern_table[i]); + return 1; + } + } + + return 0; +} + +#endif + size_t xm_get_memory_needed_for_context(const char* moddata, size_t moddata_length) { size_t memory_needed = 0; size_t offset = 60; /* Skip the first header */ @@ -153,7 +173,7 @@ char* xm_load_module(xm_context_t* ctx, const char* moddata, size_t moddata_leng mod->patterns = (xm_pattern_t*)mempool; mempool += mod->num_patterns * sizeof(xm_pattern_t); - mod->instruments = (xm_instrument_t*)mempool; + mod->instruments = (xm_instrument_t*)mempool; mempool += mod->num_instruments * sizeof(xm_instrument_t); uint16_t flags = READ_U32(offset + 14); @@ -164,7 +184,7 @@ char* xm_load_module(xm_context_t* ctx, const char* moddata, size_t moddata_leng READ_MEMCPY(mod->pattern_table, offset + 20, PATTERN_ORDER_TABLE_LENGTH); offset += header_size; - + /* Read patterns */ for(uint16_t i = 0; i < mod->num_patterns; ++i) { uint16_t packed_patterndata_size = READ_U16(offset + 7); diff --git a/src/xm_internal.h b/src/xm_internal.h index f019b82..e1aaf43 100644 --- a/src/xm_internal.h +++ b/src/xm_internal.h @@ -260,11 +260,21 @@ struct xm_sample_s { /* ----- Internal API ----- */ -/** Check the module header (first 60 bytes). +#ifdef XM_DEFENSIVE + +/** Check the module data for errors/inconsistencies. + * + * @returns 0 if everything looks OK. Module should be safe to load. + */ +int xm_check_sanity_preload(const char*, size_t); + +/** Check a loaded module for errors/inconsistencies. * * @returns 0 if everything looks OK. */ -int xm_check_header_sanity(const char*, size_t); +int xm_check_sanity_postload(xm_context_t*); + +#endif /** Get the number of bytes needed to store the module data in a * dynamically allocated blank context.