| 2127 | } |
| 2128 | |
| 2129 | void |
| 2130 | timer_sanity_check(void) |
| 2131 | { |
| 2132 | timer_element *curr; |
| 2133 | unsigned long t_id; |
| 2134 | coordxy x, y; |
| 2135 | |
| 2136 | for (curr = gt.timer_base; curr; curr = curr->next) { |
| 2137 | t_id = curr->tid; |
| 2138 | switch (curr->kind) { |
| 2139 | case TIMER_OBJECT: { |
| 2140 | /* TODO? verify that the timer type is attached to applicable |
| 2141 | object (egg for hatch, glob for shrink, and so forth) */ |
| 2142 | struct obj *obj = curr->arg.a_obj, *top; |
| 2143 | char *obj_adr = fmt_ptr((genericptr_t) obj); |
| 2144 | int owhere = obj->where; |
| 2145 | |
| 2146 | if (obj->timed == 0) { |
| 2147 | impossible("timer sanity: untimed obj %s, timer %lu", |
| 2148 | obj_adr, t_id); |
| 2149 | } |
| 2150 | x = y = 0; |
| 2151 | /* if obj is in a container, possibly a nested one, figure out |
| 2152 | where the outermost container is */ |
| 2153 | for (top = obj; top; top = top->ocontainer) |
| 2154 | if ((owhere = top->where) != OBJ_CONTAINED) |
| 2155 | break; |
| 2156 | assert(top != NULL); |
| 2157 | if (owhere == OBJ_MIGRATING |
| 2158 | || (owhere == OBJ_MINVENT && !mon_is_local(top->ocarry))) { |
| 2159 | /* migrating directly or carried by migrating monster */ |
| 2160 | ; /* not able to validate location so skip checks */ |
| 2161 | } else if (!get_obj_location(obj, &x, &y, |
| 2162 | CONTAINED_TOO | BURIED_TOO)) { |
| 2163 | /* free? or on a shop's used-up bill? */ |
| 2164 | impossible( |
| 2165 | "timer sanity: can't locate obj %s [where=%d], timer %lu", |
| 2166 | obj_adr, obj->where, t_id); |
| 2167 | } else if (!isok(x, y)) { |
| 2168 | impossible( |
| 2169 | "timer sanity: obj %s [where=%d] located at <%d,%d>, timer %lu", |
| 2170 | obj_adr, obj->where, x, y, t_id); |
| 2171 | } |
| 2172 | break; |
| 2173 | } |
| 2174 | case TIMER_MONSTER: |
| 2175 | impossible("timer sanity: unexpected monster timer %lu", t_id); |
| 2176 | break; |
| 2177 | case TIMER_LEVEL: { |
| 2178 | long lwhere = curr->arg.a_long; |
| 2179 | |
| 2180 | x = (coordxy) ((lwhere >> 16) & 0xFFFF); |
| 2181 | y = (coordxy) (lwhere & 0xFFFF); |
| 2182 | if (isok(x, y)) { |
| 2183 | /* replicate isok() in order to convince static analysis |
| 2184 | that the decoding via '& 0xFFFF' hasn't produced a value |
| 2185 | too big for levl[][] and that the cast to a narrower type |
| 2186 | hasn't intruded on the sign bit to yield a negative value; |
no test coverage detected