mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
Check cfg_meta's result before reading a row's default in default_number and gfx_cfg_window_size.
cfg.c default_number, which cfg_int and cfg_double use for a set value that does not parse, read cfg_meta(name)->def without a check, so a key without a row whose value was set and unparsable crashed there (the verifier's probe: a segmentation fault inside default_number). gfx_present.c gfx_cfg_window_size did the same for WINDOW_SIZE. Neither is reachable today: every unguarded value read has a row (tests/cfg_rows_check.py holds it so), the three guarded ones use cfg_bool, and WINDOW_SIZE has a row. default_number gives 0 for a key without a row; gfx_cfg_window_size falls back to 1920x1080 when the row or its default is missing. Taking the device profile's default there (1280x800 on a Steam Deck) would change what players get and is left for approval. Reproduced before the change with the new case in tests/cfg_parse_check.py (cfg_int and cfg_double of an unset row's key set to "abc" crashed the program); with the change both give 0 and the check passes, as do the cfg rows checks and the compile checks. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -985,9 +985,11 @@ static const char *cfg_memo_get(const char *name, int kind) {
|
||||
const char *cfg_get(const char *name) { return cfg_memo_get(name, 0); }
|
||||
const char *cfg_value(const char *name) { return cfg_memo_get(name, 1); }
|
||||
|
||||
// The row's default as a number, for a set value that does not parse.
|
||||
// The row's default as a number, for a set value that does not parse; 0 for a key without a row, whose set value
|
||||
// cfg_value hands out without one (tests/cfg_rows_check.py keeps such reads guarded).
|
||||
static double default_number(const char *name) {
|
||||
return strtod(cfg_meta(name)->def, NULL);
|
||||
const CfgMeta *m = cfg_meta(name);
|
||||
return m ? strtod(m->def, NULL) : 0;
|
||||
}
|
||||
|
||||
double cfg_double(const char *name) {
|
||||
|
||||
@@ -179,8 +179,10 @@ int gfx_cfg_fullscreen(void) { return cfg_bool("NX2NAVI_FULLSCREEN"); }
|
||||
|
||||
void gfx_cfg_window_size(int *w, int *h) {
|
||||
int x = 0, y = 0;
|
||||
if (sscanf(cfg_value("NX2NAVI_WINDOW_SIZE"), "%dx%d", &x, &y) != 2 || x < 640 || y < 360 || x > 7680 || y > 4320)
|
||||
sscanf(cfg_meta("WINDOW_SIZE")->def, "%dx%d", &x, &y); // unparsable or out of range: the default
|
||||
if (sscanf(cfg_value("NX2NAVI_WINDOW_SIZE"), "%dx%d", &x, &y) != 2 || x < 640 || y < 360 || x > 7680 || y > 4320) {
|
||||
const CfgMeta *m = cfg_meta("WINDOW_SIZE"); // unparsable or out of range: the default
|
||||
if (!m || sscanf(m->def, "%dx%d", &x, &y) != 2) x = 1920, y = 1080;
|
||||
}
|
||||
*w = x;
|
||||
*h = y;
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// cfg.c logged ("log: ...") and what the case reads back ("got: ...").
|
||||
// load cfg_load on the file; then cfg_init's check of the environment (the variables the script set)
|
||||
// full cfg_load on the file, then two cfg_set of keys the file does not have
|
||||
// norow cfg_int and cfg_double of a key without a row whose value (the environment's) does not parse
|
||||
#include <stdarg.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
@@ -80,5 +81,10 @@ int main(int argc, char **argv) {
|
||||
printf("got: vk_present %s\n", cfg_get("NX2NAVI_VK_PRESENT") ? cfg_get("NX2NAVI_VK_PRESENT") : "(unset)");
|
||||
return 0;
|
||||
}
|
||||
if (!strcmp(argv[1], "norow")) {
|
||||
if (!cfg_load(ini)) return printf("cfg_load failed\n"), 2;
|
||||
printf("got: cfg_int %d cfg_double %g\n", cfg_int("NX2NAVI_NO_ROW_CHECK"), cfg_double("NX2NAVI_NO_ROW_CHECK"));
|
||||
return 0;
|
||||
}
|
||||
return 2;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ for what it links with. The values stay as written; what is checked is what the
|
||||
word that is none of the menu's choices, and a ';' or '#' comment kept in a value, each named with its line; none
|
||||
for a file whose values fit, nor for a list with numbers in it (the menu's presets); at most 16 lines, then a count;
|
||||
- a full settings table (cfg.c CFG_MAX_KEYS): one line at load naming the first key not read, one at the first menu
|
||||
change not kept.
|
||||
change not kept;
|
||||
- a number read of a key without a row whose set value does not parse gives 0 (cfg.c default_number), not a crash.
|
||||
|
||||
No game files.
|
||||
|
||||
@@ -129,6 +130,8 @@ def main():
|
||||
'a file with 601 keys: one line at load from line 513 on', out)
|
||||
check(rc == 0 and len(set_lines) == 1 and 'VK_PRESENT is not kept' in set_lines[0],
|
||||
'two menu changes past a full table: one line', out)
|
||||
rc, out = run(exe, env, 'norow', CLEAN, work, {'NX2NAVI_NO_ROW_CHECK': 'abc'})
|
||||
check(rc == 0 and 'got: cfg_int 0 cfg_double 0' in out, 'cfg_int of a set, unparsable key without a row: 0', out)
|
||||
print(f'cfg_parse_check: {"FAILED" if bad else "ok"}')
|
||||
return 1 if bad else 0
|
||||
|
||||
|
||||
Reference in New Issue
Block a user