Validate last_hitobj on game load

Testing for `object_none` is insufficient.  Games saved before the fix
for 14cdf1b352 may have a `last_hitobj` of
`0x1ff`, which triggers an exception when constructing `icobjidx_t`.
Treat any invalid object index as `object_none`.

Reported-by: Quix0r <https://github.com/dxx-rebirth/dxx-rebirth/issues/716>
This commit is contained in:
Kp 2023-05-15 23:52:18 +00:00
parent b4e3d67725
commit 5ca2f59619
2 changed files with 17 additions and 4 deletions

View file

@ -6158,10 +6158,11 @@ void multi_object_rw_to_object(const object_rw *const obj_rw, object &obj)
obj.ctype.laser_info.parent_num = INTEL_SHORT(obj_rw->ctype.laser_info.parent_num);
obj.ctype.laser_info.parent_signature = object_signature_t{static_cast<uint16_t>(INTEL_INT(obj_rw->ctype.laser_info.parent_signature))};
obj.ctype.laser_info.creation_time = INTEL_INT(obj_rw->ctype.laser_info.creation_time);
{
const auto last_hitobj = INTEL_SHORT(obj_rw->ctype.laser_info.last_hitobj);
/* `last_hitobj` is untrusted network data, so it must be checked before use. */
if (const auto last_hitobj = INTEL_SHORT(obj_rw->ctype.laser_info.last_hitobj); vcobjidx_t::check_nothrow_index(last_hitobj))
obj.ctype.laser_info.reset_hitobj(last_hitobj);
}
else
obj.ctype.laser_info.clear_hitobj();
obj.ctype.laser_info.track_goal = INTEL_SHORT(obj_rw->ctype.laser_info.track_goal);
obj.ctype.laser_info.multiplier = INTEL_INT(obj_rw->ctype.laser_info.multiplier);
#if defined(DXX_BUILD_DESCENT_II)

View file

@ -601,7 +601,19 @@ static void state_object_rw_to_object(const object_rw *const obj_rw, object &obj
obj.ctype.laser_info.parent_num = obj_rw->ctype.laser_info.parent_num;
obj.ctype.laser_info.parent_signature = object_signature_t{static_cast<uint16_t>(obj_rw->ctype.laser_info.parent_signature)};
obj.ctype.laser_info.creation_time = obj_rw->ctype.laser_info.creation_time;
obj.ctype.laser_info.reset_hitobj(obj_rw->ctype.laser_info.last_hitobj);
/* Use vcobjidx_t so that `object_none` fails the test and uses the
* `else` path. `reset_hitobj` can accept `object_none`, but it
* cannot accept invalid indexes, such as the corrupted value
* `0x1ff` produced by certain <0.60 builds, when they ran
* `laser_info.hitobj_list[-1] = 1;` due to using `object_none`
* (`-1` back then) as if it were a valid index. That bug was
* fixed in 14cdf1b3521ff82701c58c04e47a6c1deefe8e43, but some old
* save games were corrupted by it, so trap that error here.
*/
if (const auto last_hitobj = obj_rw->ctype.laser_info.last_hitobj; vcobjidx_t::check_nothrow_index(last_hitobj))
obj.ctype.laser_info.reset_hitobj(last_hitobj);
else
obj.ctype.laser_info.clear_hitobj();
obj.ctype.laser_info.track_goal = obj_rw->ctype.laser_info.track_goal;
obj.ctype.laser_info.multiplier = obj_rw->ctype.laser_info.multiplier;
#if defined(DXX_BUILD_DESCENT_II)