From 8ae4ef9eb54ad9adae183486dd666ec2e2ea91cf Mon Sep 17 00:00:00 2001 From: Kp Date: Sat, 25 Nov 2017 01:56:51 +0000 Subject: [PATCH] Fix traps due to invalid level data `Descent 2: Counterstrike` level 9 specifies a control center trigger on a side with no wall. This is not valid. In normal play, wall_toggle silently ignored this, and newdemo_pop_ctrlcen_triggers had undefined behavior. Add a warning in wall_toggle to report levels like this. Add handling in newdemo_pop_ctrlcen_triggers to detect and suppress this bogus data. `Descent 2: Counterstrike` level 11 specifies a control center trigger on a side with no child segment. This is not valid, so newdemo_pop_ctrlcen_triggers again had undefined behavior. Add handling to detect and suppress this bogus data. Reported-by: Descender1032 --- similar/main/newdemo.cpp | 24 ++++++++++++++++++++++-- similar/main/wall.cpp | 6 ++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/similar/main/newdemo.cpp b/similar/main/newdemo.cpp index c22b2456b..4e6db4c19 100644 --- a/similar/main/newdemo.cpp +++ b/similar/main/newdemo.cpp @@ -1937,9 +1937,29 @@ static void newdemo_pop_ctrlcen_triggers() for (int i = 0; i < ControlCenterTriggers.num_links; i++) { const auto &&seg = vmsegptridx(ControlCenterTriggers.seg[i]); const auto side = ControlCenterTriggers.side[i]; - const auto &&csegp = vmsegptr(seg->children[side]); + const auto csegi = seg->children[side]; + if (csegi == segment_none) + { + /* Some levels specify control center triggers for + * segments/sides that have no wall. `Descent 2: + * Counterstrike` level 11, control center trigger 0 would + * fault without this test. + */ + continue; + } + const auto &&csegp = vmsegptr(csegi); auto cside = find_connect_side(seg, csegp); - const auto anim_num = vcwallptr(seg->sides[side].wall_num)->clip_num; + const auto wall_num = seg->sides[side].wall_num; + if (wall_num == wall_none) + { + /* Some levels specify control center triggers for + * segments/sides that have no wall. `Descent 2: + * Counterstrike` level 9, control center trigger 2 would + * fault without this test. + */ + continue; + } + const auto anim_num = vcwallptr(wall_num)->clip_num; const auto n = WallAnims[anim_num].num_frames; const auto t = WallAnims[anim_num].flags & WCF_TMAP1 ? &side::tmap_num diff --git a/similar/main/wall.cpp b/similar/main/wall.cpp index c847b7894..9d2f1d1ca 100644 --- a/similar/main/wall.cpp +++ b/similar/main/wall.cpp @@ -1071,8 +1071,10 @@ void wall_toggle(const vmsegptridx_t segp, unsigned side) #endif return; } - auto wall_num = segp->sides[side].wall_num; - if (wall_num == wall_none) { + const auto wall_num = segp->sides[side].wall_num; + if (wall_num == wall_none) + { + LevelError("Ignoring attempt to toggle wall in segment %hu, side %u: no wall exists there.", segp.get_unchecked_index(), side); return; }