Nethack crashes when you are riding a flying monster over a
pool/moat and some engulfing monster plucks you off your saddle.
After falling into the water you'll get the normal message
sequence (sink like rock ... phew, that was close; you also get
chance to teleport if you can). After the last message the game
will crash with a segmentation fault.
- reproducible; null pointer dereference in swallowed()
The crash results because dismount_steed() calls float_down(), which
calls drown(), which calls teleds(), which clears u.ustuck. So when
gulpmu calls swallowed after dismount_steed(), this line attempts to
derefernce a null pointer:
swallower = monsndx(u.ustuck->data);
This patch bypasses the float_down() in dismount steed() altogether.
That routine is meant to return the hero to the floor, and that
isn't appropriate if a purple worm just plucked you off the steed
anyway.
While this fixes the crash, a problem still exists. The
way swallowing works, the swallowing monster's location
switches to that of the hero. Since that location is
over water, the purple worm ends up drowning almost
immediately after you are swallowed, while you are
swallowed. The purple worm's death is not revealed
to you since the "The purple worm drowns." message is
conditional. This patch also adds a message when
the purple worm dies, but should this guaranteed
drowing take place?
if (cansee(mtmp->mx,mtmp->my)) {
pline("%s drowns.", Monnam(mtmp));
}
+ if (u.ustuck && u.uswallow && u.ustuck == mtmp) {
+ /* This can happen after a purple worm plucks you off a
+ flying steed while you are over water. */
+ pline("%s sinks as water rushes in and flushes you out.",
+ Monnam(mtmp));
+ }
mondead(mtmp);
if (mtmp->mhp > 0) {
rloc(mtmp);
}
/* Return the player to the floor */
+ if (reason != DISMOUNT_ENGULFED) {
in_steed_dismounting = TRUE;
(void) float_down(0L, W_SADDLE);
in_steed_dismounting = FALSE;
flags.botl = 1;
- if (reason != DISMOUNT_ENGULFED) {
- (void)encumber_msg();
- vision_full_recalc = 1;
- }
+ (void)encumber_msg();
+ vision_full_recalc = 1;
+ } else flags.botl = 1;
return;
}