core: stride-aware savestate, iNES2 helpers, -Wundef, -Wmissing-prototypes

Audit pass 5 - five distinct cleanups bundled into one omnibus.

1. Element-stride byte-swapping for savestate fields (state.h, state.c,
   fceu-endian.{h,c})

   The SFORMAT 's' field was previously {bit 31 = RLSB, bits 0..30 =
   byte size}. RLSB triggers FlipByteOrder() on MSB hosts, which
   reverses the entire entry buffer end-to-end. That is correct for a
   single primitive (size <= 8 bytes) but wrong for an array of
   multi-byte primitives - reversing the whole buffer would swap
   element 0 with element N-1 and reverse their bytes too, scrambling
   the data.

   The previous workaround was either splitting an N-element array
   into N separate single-primitive entries with distinct chunk IDs
   (n106 PlayIndex split into IDX0..IDX7) or skipping the entry
   entirely on big-endian hosts (the GEKKO #ifndef in vrc6.c / vrc7.c).
   Both approaches mean BE saves are not portable to LE and vice
   versa, and force the same workaround at every new array site.

   This pass adds proper stride support:

     * SFORMAT 's' encoding is now {bit 31 = RLSB, bits 24..30 =
       stride in bytes (0 = legacy/unset), bits 0..23 = byte size}.
       16 MiB max size, well above any actual savestate field.
     * FCEUSTATE_RLSB_ARRAY(stride) macro for the new pattern.
     * FlipByteOrderStrided() byte-swaps each element of an array
       independently. Round-trip identity verified: [01 00 00 00 ...]
       -> [00 00 00 01 ...] -> [01 00 00 00 ...].
     * state.c's SubWrite / ReadStateChunk / CheckS use new helpers
       sf_size() / sf_stride() / sf_flip() that mask the size out of
       the new bit layout and dispatch to the strided variant when
       stride < size.

   Backwards compatible: legacy single-primitive entries (size == 1,
   2, 4, 8) leave the stride bits at zero, which sf_stride() reads
   as "stride equals size" and falls through to FlipByteOrder() as
   before. No on-disk format change. Existing single-primitive RLSB
   sites are unchanged.

   The infrastructure is now in place so any future SFORMAT entry
   that is an array of multi-byte primitives can be expressed as a
   single entry (e.g. "{ buf, sizeof(buf) | FCEUSTATE_RLSB_ARRAY(4),
   "BUF." }") without splitting or skipping. The existing PlayIndex
   split and GEKKO #ifndefs are intentionally left untouched -
   migrating them would alter the on-disk savestate format and is a
   separate decision.

2. iNES1-vs-iNES2 sizing helpers (cart.h)

   Twelve sites across the codebase encoded the same conditional:

     info->iNES2 ? (info->PRGRamSize + info->PRGRamSaveSize) : default

   Sometimes for PRGRAM, sometimes for CHRRAM, sometimes in bytes,
   sometimes after dividing by 1024. The pattern is verbose and easy
   to write inconsistently.

   Added two inline helpers in cart.h:
     - CartInfo_PRGRAM_bytes(info, default_bytes)
     - CartInfo_CHRRAM_bytes(info, default_bytes)

   Migrated 9 of the 13 sites: cartram.c (2), 162.c, 163.c, 134.c,
   399.c, 478.c, 480.c, 484.c. The remaining 4 are non-helper-fitting
   variants (164.c special masking, 2 cartram SaveGameLen sites with
   different fallback semantics, mmc3.c Boogerman submapper detection).

3. -Wundef enabled permanently (Makefile.libretro)

   Zero warnings out of the box - no #if-on-undefined-macro footguns
   in the codebase. Now part of WARNING_DEFINES alongside the existing
   -Wsign-compare.

4. -Wmissing-prototypes enabled permanently (Makefile.libretro)

   Started at 198 warnings, cleared all of them:

     * Mass-static-ified ~96 functions across 75 files that were
       defined non-static but only used within their own translation
       unit. (See static_prototype_fixer.py in the development notes.)
     * K&R-style empty-parens prototypes "()" replaced with explicit
       "(void)" across all asic_*.{c,h} files - GCC treats "()" as
       "any args" and refuses to match it against a separate K&R
       definition.
     * Added missing forward declarations to public headers:
         - fds.h (FDSLoad)
         - nsf.h (NSFLoad)
         - ines.h (iNESLoad)
         - unif.h (UNIFLoad)
         - latch.h (LatchHardReset, K&R fix)
         - eeprom_93Cx6.h (eeprom_93Cx6_read, K&R fix)
       Each header gained an "#include "file.h"" where needed.
     * fds_apu.c now includes its own fds_apu.h header (was missing).
     * fds_apu.h: removed unused FDSSoundRead declaration (the function
       is internal-static).
     * cartram.h: removed unused CartRAM_close declaration (the function
       is internal-static).
     * input.h: added a centralised block of FCEU_Init* prototypes
       (Zapper, Mouse, Powerpad, Arkanoid, VirtualBoy, FKB, SuborKB,
       PEC586KB, HS, Mahjong, FamilyTrainerA/B, OekaKids, TopRider,
       BarcodeWorld, BattleBox, QuizKing, FTrainerA/B, SpaceShadow,
       LCDCompZapper, ArkanoidFC) plus FCEU_ZapperSetTolerance. These
       were previously declared as "extern" inside src/input.c.
     * Static-ified FP_FASTAPASS callbacks in 106.c, 65.c, 67.c,
       asic_h3001.c, asic_vrc3.c (those with no external callers);
       left non-static for those that have header decls or are
       referenced from sibling .c files (asic_mmc1, asic_vrc6,
       asic_vrc7, flashrom).
     * For a small set of cross-file functions where adding a header
       was disproportionate to the value (MMC5_hb, NSFMMC5_Close,
       GetKeyboard, FCEU_GetJoyJoy), placed a forward declaration
       immediately above the definition. This satisfies
       -Wmissing-prototypes (which checks for any prior declaration
       in scope) without churning the public-header layout.

5. -Wshadow partial cleanup (not enabled permanently)

   Fixed five real shadows that were either bugs or actively
   misleading:

     * src/boards/476.c: removed an inner "int i" that shadowed the
       outer loop counter.
     * src/boards/mmc5.c MMC5_hb: parameter "scanline" renamed to
       "sl_param" (was shadowing the global "scanline").
     * src/boards/n106.c DoNamcoSound: parameter "Wave" renamed to
       "WaveBuf" (was shadowing the global Wave audio buffer); also
       updated the forward declaration and the matching parameter
       on sound.h's NeoFill function pointer typedef.
     * src/boards/vrc7.c UpdateOPLNEO: same Wave -> WaveBuf rename.
     * src/ntsc/nes_ntsc_impl.h: renamed an inner loop counter "n"
       that shadowed an outer "n".
     * src/drivers/libretro/libretro.c FCEUD_RegionOverride: local
       "pal" renamed to "is_pal" (was shadowing the typedef "pal" from
       palette.h).
     * src/palette.c FCEUI_SetPaletteArray: parameter "pal" renamed
       to "data" (same shadow); driver.h declaration updated to match.

   -Wshadow itself is NOT enabled permanently because the remaining
   warnings are deliberate parameter naming conventions (XBuf in
   draw functions, X in cpu hooks) and third-party blargg ntsc code.

In addition, four files were touched as part of an MSVC-build fix
that came up mid-pass: src/fds.c, src/nsf.c, src/ines.c, and
src/drivers/libretro/libretro_dipswitch.c had snprintf() calls
introduced in pass 4 that fail to link on pre-MSVC2015 toolchains
when STATIC_LINKING=1 (the libretro-common compat_snprintf.c shim
isn't compiled in those configurations). Replaced each snprintf with
either sprintf-into-bounded-buffer (the format strings have known
maximum output) or strlcpy/strlcat for the dipswitch key-build case.
All output is still bounded; truncation happens via strl*'s normal
truncation semantics where applicable.

All added code is C89-clean (top-of-block declarations only, no
mixed decls, no // comments, INLINE macro from fceu-types.h instead
of bare "inline"). Builds clean under -std=gnu11 with -Wno-write-
strings -Wsign-compare -Wundef -Wmissing-prototypes; zero errors,
zero warnings.

Determinism audit (audit_determinism.py): no rand/time/long
double/threads issues introduced.
This commit is contained in:
U-DESKTOP-SPFP6AQ\twistedtechre
2026-05-04 04:44:52 +02:00
parent 492b335705
commit 6359a0b36e
105 changed files with 847 additions and 660 deletions

View File

@@ -26,7 +26,7 @@
#include <libretro.h>
#include <streams/file_stream.h>
RFILE* rfopen(const char *path, const char *mode)
static RFILE* rfopen(const char *path, const char *mode)
{
RFILE *output = NULL;
unsigned int retro_mode = RETRO_VFS_FILE_ACCESS_READ;
@@ -67,7 +67,7 @@ RFILE* rfopen(const char *path, const char *mode)
return output;
}
int rfclose(RFILE* stream)
static int rfclose(RFILE* stream)
{
if (!stream)
return EOF;
@@ -75,7 +75,7 @@ int rfclose(RFILE* stream)
return filestream_close(stream);
}
int64_t rftell(RFILE* stream)
static int64_t rftell(RFILE* stream)
{
if (!stream)
return -1;
@@ -83,7 +83,7 @@ int64_t rftell(RFILE* stream)
return filestream_tell(stream);
}
int64_t rfseek(RFILE* stream, int64_t offset, int origin)
static int64_t rfseek(RFILE* stream, int64_t offset, int origin)
{
int seek_position = -1;
@@ -106,7 +106,7 @@ int64_t rfseek(RFILE* stream, int64_t offset, int origin)
return filestream_seek(stream, offset, seek_position);
}
int64_t rfread(void* buffer,
static int64_t rfread(void* buffer,
size_t elem_size, size_t elem_count, RFILE* stream)
{
if (!stream || (elem_size == 0) || (elem_count == 0))
@@ -115,7 +115,7 @@ int64_t rfread(void* buffer,
return (filestream_read(stream, buffer, elem_size * elem_count) / elem_size);
}
char *rfgets(char *buffer, int maxCount, RFILE* stream)
static char *rfgets(char *buffer, int maxCount, RFILE* stream)
{
if (!stream)
return NULL;
@@ -123,7 +123,7 @@ char *rfgets(char *buffer, int maxCount, RFILE* stream)
return filestream_gets(stream, buffer, maxCount);
}
int rfgetc(RFILE* stream)
static int rfgetc(RFILE* stream)
{
if (!stream)
return EOF;
@@ -131,7 +131,7 @@ int rfgetc(RFILE* stream)
return filestream_getc(stream);
}
int64_t rfwrite(void const* buffer,
static int64_t rfwrite(void const* buffer,
size_t elem_size, size_t elem_count, RFILE* stream)
{
if (!stream || (elem_size == 0) || (elem_count == 0))
@@ -140,7 +140,7 @@ int64_t rfwrite(void const* buffer,
return (filestream_write(stream, buffer, elem_size * elem_count) / elem_size);
}
int rfputc(int character, RFILE * stream)
static int rfputc(int character, RFILE * stream)
{
if (!stream)
return EOF;
@@ -148,7 +148,7 @@ int rfputc(int character, RFILE * stream)
return filestream_putc(stream, character);
}
int64_t rfflush(RFILE * stream)
static int64_t rfflush(RFILE * stream)
{
if (!stream)
return EOF;
@@ -156,7 +156,7 @@ int64_t rfflush(RFILE * stream)
return filestream_flush(stream);
}
int rfprintf(RFILE * stream, const char * format, ...)
static int rfprintf(RFILE * stream, const char * format, ...)
{
int result;
va_list vl;
@@ -170,17 +170,17 @@ int rfprintf(RFILE * stream, const char * format, ...)
return result;
}
int rferror(RFILE* stream)
static int rferror(RFILE* stream)
{
return filestream_error(stream);
}
int rfeof(RFILE* stream)
static int rfeof(RFILE* stream)
{
return filestream_eof(stream);
}
int rfscanf(RFILE * stream, const char * format, ...)
static int rfscanf(RFILE * stream, const char * format, ...)
{
int result;
va_list vl;

View File

@@ -221,7 +221,7 @@
#define RFILE_HINT_UNBUFFERED (1 << 8)
int64_t retro_vfs_file_seek_internal(
static int64_t retro_vfs_file_seek_internal(
libretro_vfs_implementation_file *stream,
int64_t offset, int whence)
{

View File

@@ -308,6 +308,7 @@ extern int zapper_sensor_invert_option;
/* emulator-specific callback functions */
const char *GetKeyboard(void); /* used by src/boards/transformer.c */
const char * GetKeyboard(void)
{
return "";
@@ -406,7 +407,7 @@ void FCEUD_DispMessage(enum retro_log_level level, unsigned duration, const char
}
}
void FCEUD_SoundToggle (void)
static void FCEUD_SoundToggle (void)
{
FCEUI_SetSoundVolume(sndvolume);
}
@@ -1904,20 +1905,20 @@ static void retro_set_custom_palette(void)
*/
static void FCEUD_RegionOverride(unsigned region)
{
unsigned pal = 0;
unsigned is_pal = 0;
unsigned d = 0;
switch (region)
{
case 0: /* auto */
d = (systemRegion >> 1) & 1;
pal = systemRegion & 1;
is_pal = systemRegion & 1;
break;
case 1: /* ntsc */
FCEUD_DispMessage(RETRO_LOG_INFO, 2000, "System: NTSC");
break;
case 2: /* pal */
pal = 1;
is_pal = 1;
FCEUD_DispMessage(RETRO_LOG_INFO, 2000, "System: PAL");
break;
case 3: /* dendy */
@@ -1927,7 +1928,7 @@ static void FCEUD_RegionOverride(unsigned region)
}
dendy = d;
FCEUI_SetVidSystem(pal);
FCEUI_SetVidSystem(is_pal);
ResetPalette();
}
@@ -2458,7 +2459,7 @@ static void check_variables(bool startup)
update_option_visibility();
}
void add_powerpad_input(unsigned port, uint32_t variant, uint32_t *ppdata) {
static void add_powerpad_input(unsigned port, uint32_t variant, uint32_t *ppdata) {
unsigned k;
const uint32_t* map = powerpadmap;
for (k = 0 ; k < 12 ; k++)
@@ -2466,7 +2467,7 @@ void add_powerpad_input(unsigned port, uint32_t variant, uint32_t *ppdata) {
*ppdata |= (1 << k);
}
void add_fkb_input(unsigned port, uint32_t variant, uint8_t *fkbkeys) {
static void add_fkb_input(unsigned port, uint32_t variant, uint8_t *fkbkeys) {
unsigned k;
const uint32_t* map = fkbmap;
for (k = 0 ; k < 0x48 ; k++)
@@ -2476,7 +2477,7 @@ void add_fkb_input(unsigned port, uint32_t variant, uint8_t *fkbkeys) {
fkbkeys[k]=0;
}
void add_suborkey_input(unsigned port, uint32_t variant, uint8_t *suborkeys) {
static void add_suborkey_input(unsigned port, uint32_t variant, uint8_t *suborkeys) {
unsigned k;
const uint32_t* map = suborkbmap;
for (k = 0 ; k < 0x65 ; k++)
@@ -2488,7 +2489,7 @@ void add_suborkey_input(unsigned port, uint32_t variant, uint8_t *suborkeys) {
static int mzx = 0, mzy = 0;
void get_mouse_input(unsigned port, uint32_t variant, uint32_t *mousedata)
static void get_mouse_input(unsigned port, uint32_t variant, uint32_t *mousedata)
{
int min_width, min_height, max_width, max_height;
@@ -2910,7 +2911,7 @@ static void FCEUD_UpdateInput(void)
palette_switch_counter = 0;
}
void FCEUD_Update(uint8_t *XBuf, int32_t *Buffer, int Count)
static void FCEUD_Update(uint8_t *XBuf, int32_t *Buffer, int Count)
{
}

View File

@@ -4,7 +4,6 @@
#include <string.h>
#include <compat/strl.h>
#include "../../fceu.h"
#include "../../fceu-types.h"
#include "../../vsuni.h"
@@ -1110,8 +1109,15 @@ static void make_core_options(struct retro_core_option_v2_definition *vs_core_op
memset(&vs_core_options[i], 0,
sizeof(struct retro_core_option_v2_definition));
/* Set core key and sanitize string */
snprintf(key, sizeof(key), "fceumm_dipswitch_%s-%s", game_name, option_name);
/* Set core key and sanitize string. Build "fceumm_dipswitch_<game>-<option>"
* with strlcpy/strlcat instead of snprintf, since snprintf isn't
* available on pre-MSVC2015 unless compat_snprintf.c is linked
* (some build configurations omit it). strlcpy/strlcat truncate
* safely if the inputs together would overflow key[]. */
strlcpy(key, "fceumm_dipswitch_", sizeof(key));
strlcat(key, game_name, sizeof(key));
strlcat(key, "-", sizeof(key));
strlcat(key, option_name, sizeof(key));
{
size_t key_size = strlen(key) + 1;
core_key[i] = calloc(key_size, sizeof(char));