follow-up for put_saddle_on_mon()

Commit 1acc2727 helped ensure that the which_armor(mtmp, W_SADDLE)
test at the top of put_saddle_on_mon() wouldn't lead to an obj
leak.

This commit covers off the adjacent can_saddle() test in
put_saddle_on_mon(), because if that failed, it could also lead
to a memory leak of the saddle obj passed by the caller.

- have put_saddle_on_mon() create and use its own saddle obj
  if a NULL saddle obj is passed, instead of having to do that
  in the caller.
- where an existing saddle obj needs to be passed from the caller,
  ensure that the caller has done its own can_saddle(mon) check prior
  to calling put_saddle_on_mon(), so that the can_saddle() test
  in put_saddle_on_mon() won't fail.
- lastly, add an impossible() to put_saddle_on_mon() to catch
  a failure when a saddle obj is passed from the caller and either
  test has failed, just in case. That should not happen with any of
  the existing cases now, but it will provide some bullet-proofing
  for new code, new callers.
This commit is contained in:
nhmall
2025-01-20 14:37:46 -05:00
parent 1acc272718
commit 61f969e88b
6 changed files with 25 additions and 16 deletions
+1 -1
View File
@@ -3056,7 +3056,7 @@ extern struct obj *findgold(struct obj *) NO_NNARGS;
extern void rider_cant_reach(void); extern void rider_cant_reach(void);
extern boolean can_saddle(struct monst *) NONNULLARG1; extern boolean can_saddle(struct monst *) NONNULLARG1;
extern int use_saddle(struct obj *) NONNULLARG1; extern int use_saddle(struct obj *) NONNULLARG1;
extern void put_saddle_on_mon(struct obj *, struct monst *) NONNULLARG12; extern void put_saddle_on_mon(struct obj *, struct monst *) NONNULLARG2;
extern boolean can_ride(struct monst *) NONNULLARG1; extern boolean can_ride(struct monst *) NONNULLARG1;
extern int doride(void); extern int doride(void);
extern boolean mount_steed(struct monst *, boolean) NO_NNARGS; extern boolean mount_steed(struct monst *, boolean) NO_NNARGS;
+4 -7
View File
@@ -191,7 +191,6 @@ struct monst *
makedog(void) makedog(void)
{ {
struct monst *mtmp; struct monst *mtmp;
struct obj *otmp;
const char *petname; const char *petname;
int pettype; int pettype;
@@ -231,12 +230,10 @@ makedog(void)
svc.context.startingpet_mid = mtmp->m_id; svc.context.startingpet_mid = mtmp->m_id;
if (!u.uroleplay.pauper) { if (!u.uroleplay.pauper) {
/* initial horses start wearing a saddle (pauper hero excluded) */ /* initial horses start wearing a saddle (pauper hero excluded) */
if (pettype == PM_PONY if (pettype == PM_PONY) {
&& (otmp = mksobj(SADDLE, TRUE, FALSE)) != 0) { /* NULL obj arg means put_saddle_on_mon()
/* pseudo initial inventory; saddle is not actually in hero's * will carry out the saddle creation */
* invent so assume that update_inventory() isn't needed */ put_saddle_on_mon((struct obj *) 0, mtmp);
fully_identify_obj(otmp);
put_saddle_on_mon(otmp, mtmp);
} }
} }
} else { } else {
+3 -3
View File
@@ -1439,9 +1439,9 @@ makemon(
if (!rn2(100) && is_domestic(ptr) if (!rn2(100) && is_domestic(ptr)
&& can_saddle(mtmp) && !which_armor(mtmp, W_SADDLE)) { && can_saddle(mtmp) && !which_armor(mtmp, W_SADDLE)) {
struct obj *otmp = mksobj(SADDLE, TRUE, FALSE); /* NULL obj arg means put_saddle_on_mon()
* will create the saddle itself */
put_saddle_on_mon(otmp, mtmp); put_saddle_on_mon((struct obj *) 0, mtmp);
} }
} else { } else {
+3 -3
View File
@@ -3237,9 +3237,9 @@ create_particular_creation(
set_malign(mtmp); set_malign(mtmp);
} }
if (d->saddled && can_saddle(mtmp) && !which_armor(mtmp, W_SADDLE)) { if (d->saddled && can_saddle(mtmp) && !which_armor(mtmp, W_SADDLE)) {
struct obj *otmp = mksobj(SADDLE, TRUE, FALSE); /* NULL obj arg means put_saddle_on_mon()
* will create the saddle itself */
put_saddle_on_mon(otmp, mtmp); put_saddle_on_mon((struct obj *) 0, mtmp);
} }
if (d->hidden if (d->hidden
&& ((is_hider(mtmp->data) && mtmp->data->mlet != S_MIMIC) && ((is_hider(mtmp->data) && mtmp->data->mlet != S_MIMIC)
+1 -1
View File
@@ -2307,7 +2307,7 @@ create_object(object *o, struct mkroom *croom)
; /* ['otmp' remains on floor] */ ; /* ['otmp' remains on floor] */
} else { } else {
remove_object(otmp); remove_object(otmp);
if (otmp->otyp == SADDLE) if (otmp->otyp == SADDLE && can_saddle(invent_carrying_monster))
put_saddle_on_mon(otmp, invent_carrying_monster); put_saddle_on_mon(otmp, invent_carrying_monster);
else else
(void) mpickobj(invent_carrying_monster, otmp); (void) mpickobj(invent_carrying_monster, otmp);
+13 -1
View File
@@ -131,6 +131,7 @@ use_saddle(struct obj *otmp)
if (otmp->owornmask) if (otmp->owornmask)
remove_worn_item(otmp, FALSE); remove_worn_item(otmp, FALSE);
freeinv(otmp); freeinv(otmp);
/* !can_saddle(mtmp) already eliminated above */
put_saddle_on_mon(otmp, mtmp); put_saddle_on_mon(otmp, mtmp);
} else } else
pline("%s resists!", Monnam(mtmp)); pline("%s resists!", Monnam(mtmp));
@@ -140,8 +141,19 @@ use_saddle(struct obj *otmp)
void void
put_saddle_on_mon(struct obj *saddle, struct monst *mtmp) put_saddle_on_mon(struct obj *saddle, struct monst *mtmp)
{ {
if (!can_saddle(mtmp) || which_armor(mtmp, W_SADDLE)) if (!can_saddle(mtmp) || which_armor(mtmp, W_SADDLE)) {
if (saddle)
impossible("put_saddle_on_mon: saddle obj could get orphaned");
return; return;
}
if (!saddle) {
if ((saddle = mksobj(SADDLE, TRUE, FALSE)) != 0) {
fully_identify_obj(saddle);
/* mpickobj can later override identification if out-of-view */
} else {
return;
}
}
if (mpickobj(mtmp, saddle)) if (mpickobj(mtmp, saddle))
panic("merged saddle?"); panic("merged saddle?");
mtmp->misc_worn_check |= W_SADDLE; mtmp->misc_worn_check |= W_SADDLE;