From 59c3913b2fbb01392a8dd2771fa25db4df943da3 Mon Sep 17 00:00:00 2001 From: Markus Armbruster Date: Sun, 15 Feb 2009 08:47:43 +0100 Subject: [PATCH] Take care not to supply from self Change s_commod() not to use the supply sink as source. As explained in the message of the commit before the previous one, using the sink as source makes it impossible for callers to safely keep a copy of the sink across a supply call. All current users do that. Some were safe anyway, some were not: * fort_fire() was safe, because a fort draws shells only when it has none. * shp_fire() was unsafe for ships with capability supply and ammo use greater than 1. No such ship exists in the stock game. * shp_dchrg() was unsafe for ships with both capabilities dchrg and supply. Same for shp_torp() and capability torp, and shp_missile_defense() and capability anti-missile. No such ship exists in the stock game. * lnd_fire(), supp() and get_dlist() were safe, because they draw shells only when they have less than their ammo need, and then they don't supply any. * mission_pln_equip() was unsafe when equipping planes with shells in supply sources. * landmine() was unsafe for land units with both capability engineer and supply. No such land units exist in the stock game. * load() and lload() were unsafe for loadable supply units, but the supply use there was disabled in commit 65410d16 because of another bug. * ask_olist() and att_reacting_units() were safe, because lnd_can_attack() excludes supply units. In the stock game, planes flying interception or support missions, abms intercepting ballistic missiles, launch of missiles or anti-sats could conjure up shells, triggering a seqno mismatch oops. In games with unusual customizations, this could also happen with supply ships firing guns or torpedoes, dropping depth charges, or shooting down marine missiles, and in the lmine command. --- src/lib/subs/supply.c | 67 +++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 35 deletions(-) diff --git a/src/lib/subs/supply.c b/src/lib/subs/supply.c index 57a60a420..f81ece537 100644 --- a/src/lib/subs/supply.c +++ b/src/lib/subs/supply.c @@ -130,34 +130,40 @@ s_commod(struct empobj *sink, short *vec, return 1; wanted -= vec[type]; - /* try to get it from sector we're in */ getsect(x, y, &dest); - getsect(x, y, §); - if (sect.sct_own == own) { - if (!opt_NOFOOD && type == I_FOOD) - minimum = 1 + (int)ceil(food_needed(sect.sct_item, - etu_per_update)); - if (sect.sct_item[type] - wanted >= minimum) { - sect.sct_item[type] -= wanted; - if (actually_doit) { - vec[type] += wanted; - putsect(§); - put_empobj(sink->ef_type, sink->uid, sink); - } - return 1; - } else if (sect.sct_item[type] - minimum > 0) { - wanted -= sect.sct_item[type] - minimum; - sect.sct_item[type] = minimum; - if (actually_doit) { - vec[type] += sect.sct_item[type] - minimum; - putsect(§); + + /* try to get it from sector we're in */ + if (sink->ef_type != EF_SECTOR) { + getsect(x, y, §); + if (sect.sct_own == own) { + if (!opt_NOFOOD && type == I_FOOD) + minimum = 1 + (int)ceil(food_needed(sect.sct_item, + etu_per_update)); + if (sect.sct_item[type] - wanted >= minimum) { + sect.sct_item[type] -= wanted; + if (actually_doit) { + vec[type] += wanted; + putsect(§); + put_empobj(sink->ef_type, sink->uid, sink); + } + return 1; + } else if (sect.sct_item[type] - minimum > 0) { + wanted -= sect.sct_item[type] - minimum; + sect.sct_item[type] = minimum; + if (actually_doit) { + vec[type] += sect.sct_item[type] - minimum; + putsect(§); + } } } } + /* look for a headquarters or warehouse */ lookrange = tfact(own, 10.0); snxtsct_dist(&ns, x, y, lookrange); while (nxtsct(&ns, §) && wanted) { + if (ns.curdist == 0) + continue; if (sect.sct_own != own) continue; if ((sect.sct_type != SCT_WAREH) && @@ -174,10 +180,8 @@ s_commod(struct empobj *sink, short *vec, if (!opt_NOFOOD && type == I_FOOD) minimum = 1 + (int)ceil(food_needed(sect.sct_item, etu_per_update)); - if (sect.sct_item[type] <= minimum) { - /* Don't bother... */ + if (sect.sct_item[type] <= minimum) continue; - } ip = &ichr[type]; dp = &dchr[sect.sct_type]; packing = ip->i_pkg[dp->d_pkg]; @@ -231,11 +235,11 @@ s_commod(struct empobj *sink, short *vec, /* look for an owned ship in a harbor */ snxtitem_dist(&ni, EF_SHIP, x, y, lookrange); - while (nxtitem(&ni, &ship) && wanted) { + if (sink->ef_type == EF_SHIP && sink->uid == ship.shp_uid) + continue; if (ship.shp_own != own) continue; - if (!(mchr[(int)ship.shp_type].m_flags & M_SUPPLY)) continue; getsect(ship.shp_x, ship.shp_y, §); @@ -248,10 +252,8 @@ s_commod(struct empobj *sink, short *vec, if (!opt_NOFOOD && type == I_FOOD) minimum = 1 + (int)ceil(food_needed(ship.shp_item, etu_per_update)); - if (ship.shp_item[type] <= minimum) { - /* Don't bother... */ + if (ship.shp_item[type] <= minimum) continue; - } ip = &ichr[type]; dp = &dchr[sect.sct_type]; packing = ip->i_pkg[dp->d_pkg]; @@ -303,10 +305,11 @@ s_commod(struct empobj *sink, short *vec, /* look for an owned supply unit */ snxtitem_dist(&ni, EF_LAND, x, y, lookrange); - while (nxtitem(&ni, &land) && wanted) { int min; + if (sink->ef_type == EF_LAND && sink->uid == land.lnd_uid) + continue; if (land.lnd_own != own) continue; @@ -443,13 +446,10 @@ lnd_could_be_supplied(struct lndstr *lp) food_needed = get_minimum(lp, I_FOOD); food = lp->lnd_item[I_FOOD]; if (food < food_needed) { - lp->lnd_item[I_FOOD] = 0; - putland(lp->lnd_uid, lp); res = s_commod((struct empobj *)lp, lp->lnd_item, I_FOOD, food_needed, lchr[lp->lnd_type].l_item[I_FOOD], 0); lp->lnd_item[I_FOOD] = food; - putland(lp->lnd_uid, lp); if (!res) return 0; } @@ -458,13 +458,10 @@ lnd_could_be_supplied(struct lndstr *lp) shells_needed = lchr[lp->lnd_type].l_ammo; shells = lp->lnd_item[I_SHELL]; if (shells < shells_needed) { - lp->lnd_item[I_SHELL] = 0; - putland(lp->lnd_uid, lp); res = s_commod((struct empobj *)lp, lp->lnd_item, I_SHELL, shells_needed, lchr[lp->lnd_type].l_item[I_SHELL], 0); lp->lnd_item[I_SHELL] = shells; - putland(lp->lnd_uid, lp); if (!res) return 0; } -- 2.43.0