Add more validation to midend deserialisation routine

These are all pretty obvious and enforce constraints that would
otherwise be enforced by segfault.
This commit is contained in:
Ben Harris
2022-10-16 18:31:54 +01:00
parent 879a6922b0
commit 02e5e93046

View File

@ -2265,15 +2265,15 @@ static const char *midend_deserialise_internal(
} else if (!strcmp(key, "TIME")) { } else if (!strcmp(key, "TIME")) {
data.elapsed = (float)atof(val); data.elapsed = (float)atof(val);
} else if (!strcmp(key, "NSTATES")) { } else if (!strcmp(key, "NSTATES")) {
if (data.states) {
ret = "Two state counts provided in save file";
goto cleanup;
}
data.nstates = atoi(val); data.nstates = atoi(val);
if (data.nstates <= 0) { if (data.nstates <= 0) {
ret = "Number of states in save file was negative"; ret = "Number of states in save file was negative";
goto cleanup; goto cleanup;
} }
if (data.states) {
ret = "Two state counts provided in save file";
goto cleanup;
}
data.states = snewn(data.nstates, struct midend_state_entry); data.states = snewn(data.nstates, struct midend_state_entry);
for (i = 0; i < data.nstates; i++) { for (i = 0; i < data.nstates; i++) {
data.states[i].state = NULL; data.states[i].state = NULL;
@ -2282,18 +2282,19 @@ static const char *midend_deserialise_internal(
} }
} else if (!strcmp(key, "STATEPOS")) { } else if (!strcmp(key, "STATEPOS")) {
data.statepos = atoi(val); data.statepos = atoi(val);
} else if (!strcmp(key, "MOVE")) { } else if (!strcmp(key, "MOVE") ||
!strcmp(key, "SOLVE") ||
!strcmp(key, "RESTART")) {
if (!data.states) {
ret = "No state count provided in save file";
goto cleanup;
}
gotstates++; gotstates++;
if (!strcmp(key, "MOVE"))
data.states[gotstates].movetype = MOVE; data.states[gotstates].movetype = MOVE;
data.states[gotstates].movestr = val; else if (!strcmp(key, "SOLVE"))
val = NULL;
} else if (!strcmp(key, "SOLVE")) {
gotstates++;
data.states[gotstates].movetype = SOLVE; data.states[gotstates].movetype = SOLVE;
data.states[gotstates].movestr = val; else
val = NULL;
} else if (!strcmp(key, "RESTART")) {
gotstates++;
data.states[gotstates].movetype = RESTART; data.states[gotstates].movetype = RESTART;
data.states[gotstates].movestr = val; data.states[gotstates].movestr = val;
val = NULL; val = NULL;
@ -2305,12 +2306,20 @@ static const char *midend_deserialise_internal(
} }
data.params = me->ourgame->default_params(); data.params = me->ourgame->default_params();
if (!data.parstr) {
ret = "Long-term parameters in save file are missing";
goto cleanup;
}
me->ourgame->decode_params(data.params, data.parstr); me->ourgame->decode_params(data.params, data.parstr);
if (me->ourgame->validate_params(data.params, true)) { if (me->ourgame->validate_params(data.params, true)) {
ret = "Long-term parameters in save file are invalid"; ret = "Long-term parameters in save file are invalid";
goto cleanup; goto cleanup;
} }
data.cparams = me->ourgame->default_params(); data.cparams = me->ourgame->default_params();
if (!data.cparstr) {
ret = "Short-term parameters in save file are missing";
goto cleanup;
}
me->ourgame->decode_params(data.cparams, data.cparstr); me->ourgame->decode_params(data.cparams, data.cparstr);
if (me->ourgame->validate_params(data.cparams, false)) { if (me->ourgame->validate_params(data.cparams, false)) {
ret = "Short-term parameters in save file are invalid"; ret = "Short-term parameters in save file are invalid";
@ -2340,6 +2349,10 @@ static const char *midend_deserialise_internal(
ret = "Game position in save file is out of range"; ret = "Game position in save file is out of range";
} }
if (!data.states) {
ret = "No state count provided in save file";
goto cleanup;
}
data.states[0].state = me->ourgame->new_game( data.states[0].state = me->ourgame->new_game(
me, data.cparams, data.privdesc ? data.privdesc : data.desc); me, data.cparams, data.privdesc ? data.privdesc : data.desc);