From a44234307651102e6778dcc62b48b973840d7412 Mon Sep 17 00:00:00 2001 From: rubidium Date: Fri, 4 Sep 2009 20:40:15 +0000 Subject: [PATCH] (svn r17417) [0.7] -Backport from trunk: - Fix: Incomplete check on validity of industry type when building industries (r17413) - Fix: [Squirrel] Guard against Squirrel stack overflows (r17403) - Fix: [NoAI] During every save a few slots on the Squirrel stack were leaked (r17402) - Fix: [NoAI] Several AITile::* functions did not check whether their parameters were valid (r17378) --- src/3rdparty/squirrel/squirrel/squtils.h | 2 +- src/3rdparty/squirrel/squirrel/sqvm.cpp | 14 +++++++++++++- src/ai/api/ai_tile.cpp | 12 ++++++++++++ src/industry_cmd.cpp | 8 ++++++-- src/script/squirrel.cpp | 2 +- 5 files changed, 33 insertions(+), 5 deletions(-) diff --git a/src/3rdparty/squirrel/squirrel/squtils.h b/src/3rdparty/squirrel/squirrel/squtils.h index b6a436e4a8..55febe38c9 100644 --- a/src/3rdparty/squirrel/squirrel/squtils.h +++ b/src/3rdparty/squirrel/squirrel/squtils.h @@ -88,7 +88,7 @@ public: } SQUnsignedInteger capacity() { return _allocated; } inline T &back() const { return _vals[_size - 1]; } - inline T& operator[](SQUnsignedInteger pos) const{ return _vals[pos]; } + inline T& operator[](SQUnsignedInteger pos) const{ assert(pos < _allocated); return _vals[pos]; } T* _vals; private: void _realloc(SQUnsignedInteger newsize) diff --git a/src/3rdparty/squirrel/squirrel/sqvm.cpp b/src/3rdparty/squirrel/squirrel/sqvm.cpp index 036016cd19..d1ae4e64e8 100644 --- a/src/3rdparty/squirrel/squirrel/sqvm.cpp +++ b/src/3rdparty/squirrel/squirrel/sqvm.cpp @@ -1503,7 +1503,19 @@ void SQVM::Pop(SQInteger n) { } } -void SQVM::Push(const SQObjectPtr &o) { _stack[_top++] = o; } +void SQVM::Push(const SQObjectPtr &o) { + /* Normally the stack shouldn't get this full, sometimes it might. As of now + * all cases have been bugs in "our" (OpenTTD) code. Trigger an assert for + * all debug builds and for the release builds just increase the stack size. + * This way getting a false positive isn't that bad (releases work fine) and + * if there is something fishy it can be caught in RCs/nightlies. */ +#ifdef NDEBUG + if (_top >= (int)_stack.capacity()) _stack.resize(2 * _stack.capacity()); +#else + assert(_top < (int)_stack.capacity()); +#endif + _stack[_top++] = o; +} SQObjectPtr &SQVM::Top() { return _stack[_top-1]; } SQObjectPtr &SQVM::PopGet() { return _stack[--_top]; } SQObjectPtr &SQVM::GetUp(SQInteger n) { return _stack[_top+n]; } diff --git a/src/ai/api/ai_tile.cpp b/src/ai/api/ai_tile.cpp index 3eca6481b9..b292ba603e 100644 --- a/src/ai/api/ai_tile.cpp +++ b/src/ai/api/ai_tile.cpp @@ -87,31 +87,43 @@ /* static */ bool AITile::HasTreeOnTile(TileIndex tile) { + if (!::IsValidTile(tile)) return false; + return ::IsTileType(tile, MP_TREES); } /* static */ bool AITile::IsFarmTile(TileIndex tile) { + if (!::IsValidTile(tile)) return false; + return (::IsTileType(tile, MP_CLEAR) && ::IsClearGround(tile, CLEAR_FIELDS)); } /* static */ bool AITile::IsRockTile(TileIndex tile) { + if (!::IsValidTile(tile)) return false; + return (::IsTileType(tile, MP_CLEAR) && ::IsClearGround(tile, CLEAR_ROCKS)); } /* static */ bool AITile::IsRoughTile(TileIndex tile) { + if (!::IsValidTile(tile)) return false; + return (::IsTileType(tile, MP_CLEAR) && ::IsClearGround(tile, CLEAR_ROUGH)); } /* static */ bool AITile::IsSnowTile(TileIndex tile) { + if (!::IsValidTile(tile)) return false; + return (::IsTileType(tile, MP_CLEAR) && ::IsClearGround(tile, CLEAR_SNOW)); } /* static */ bool AITile::IsDesertTile(TileIndex tile) { + if (!::IsValidTile(tile)) return false; + return (::IsTileType(tile, MP_CLEAR) && ::IsClearGround(tile, CLEAR_DESERT)); } diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp index e382ab8e28..fd3684a371 100644 --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -1642,7 +1642,10 @@ static Industry *CreateNewIndustryHelper(TileIndex tile, IndustryType type, DoCo */ CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text) { - const IndustrySpec *indspec = GetIndustrySpec(GB(p1, 0, 16)); + IndustryType it = GB(p1, 0, 16); + if (it >= NUM_INDUSTRYTYPES) return CMD_ERROR; + + const IndustrySpec *indspec = GetIndustrySpec(it); const Industry *ind = NULL; /* Check if the to-be built/founded industry is available for this climate. */ @@ -1681,7 +1684,8 @@ CommandCost CmdBuildIndustry(TileIndex tile, DoCommandFlag flags, uint32 p1, uin } else { int count = indspec->num_table; const IndustryTileTable * const *itt = indspec->table; - int num = Clamp(GB(p1, 16, 16), 0, count - 1); + int num = GB(p1, 16, 16); + if (num >= count) return CMD_ERROR; _error_message = STR_0239_SITE_UNSUITABLE; do { diff --git a/src/script/squirrel.cpp b/src/script/squirrel.cpp index 1dd407589a..410943b545 100644 --- a/src/script/squirrel.cpp +++ b/src/script/squirrel.cpp @@ -222,7 +222,7 @@ bool Squirrel::CallMethod(HSQOBJECT instance, const char *method_name, HSQOBJECT if (ret != NULL) sq_getstackobj(vm, -1, ret); /* Reset the top, but don't do so for the AI main function, as we need * a correct stack when resuming. */ - if (!this->IsSuspended()) sq_settop(this->vm, top); + if (suspend == -1) sq_settop(this->vm, top); /* Restore the return-value location. */ this->vm->_suspended_target = last_target;