diff --git a/src/engine.cpp b/src/engine.cpp index d08fbef329..8774b0b3ea 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -497,6 +497,9 @@ void SetCachedEngineCounts() } } +/** + * Initialise the engine pool with the data from the original vehicles. + */ void SetupEngines() { DeleteWindowByClass(WC_ENGINE_PREVIEW); @@ -506,6 +509,9 @@ void SetupEngines() const EngineIDMapping *end = _engine_mngr.End(); uint index = 0; for (const EngineIDMapping *eid = _engine_mngr.Begin(); eid != end; eid++, index++) { + /* Assert is safe; there won't be more than 256 original vehicles + * in any case, and we just cleaned the pool. */ + assert(Engine::CanAllocateItem()); const Engine *e = new Engine(eid->type, eid->internal_id); assert(e->index == index); } diff --git a/src/saveload/afterload.cpp b/src/saveload/afterload.cpp index f73ef21894..17ac9bc814 100644 --- a/src/saveload/afterload.cpp +++ b/src/saveload/afterload.cpp @@ -782,11 +782,18 @@ bool AfterLoadGame() case STATION_TRUCK: case STATION_BUS: if (IsSavegameVersionBefore(6)) { + /* Before version 5 you could not have more than 250 stations. + * Version 6 adds large maps, so you could only place 253*253 + * road stops on a map (no freeform edges) = 64009. So, yes + * someone could in theory create such a full map to trigger + * this assertion, it's safe to assume that's only something + * theoretical and does not happen in normal games. */ + assert(RoadStop::CanAllocateItem()); + /* From this version on there can be multiple road stops of the * same type per station. Convert the existing stops to the new * internal data structure. */ RoadStop *rs = new RoadStop(t); - if (rs == NULL) error("Too many road stops in savegame"); RoadStop **head = IsTruckStop(t) ? &st->truck_stops : &st->bus_stops; @@ -1928,6 +1935,12 @@ bool AfterLoadGame() ObjectType type = GetObjectType(t); int size = type == OBJECT_HQ ? 2 : 1; + if (!Object::CanAllocateItem()) { + /* Nice... you managed to place 64k lighthouses and + * antennae on the map... boohoo. */ + SlError(STR_ERROR_TOO_MANY_OBJECTS); + } + Object *o = new Object(); o->location.tile = t; o->location.w = size; @@ -2024,6 +2037,10 @@ bool AfterLoadGame() FOR_ALL_STATIONS(st) { std::list::iterator iter; for (iter = st->loading_vehicles.begin(); iter != st->loading_vehicles.end(); ++iter) { + /* There are always as many CargoPayments as Vehicles. We need to make the + * assert() in Pool::GetNew() happy by calling CanAllocateItem(). */ + assert_compile(CargoPaymentPool::MAX_SIZE == VehiclePool::MAX_SIZE); + assert(CargoPayment::CanAllocateItem()); Vehicle *v = *iter; if (v->cargo_payment == NULL) v->cargo_payment = new CargoPayment(v); } diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp index ce3281715a..ae759f4d17 100644 --- a/src/saveload/saveload.cpp +++ b/src/saveload/saveload.cpp @@ -472,7 +472,7 @@ static void SlNullPointers() * @note This function does never return as it throws an exception to * break out of all the saveload code. */ -static void NORETURN SlError(StringID string, const char *extra_msg = NULL) +void NORETURN SlError(StringID string, const char *extra_msg) { /* Distinguish between loading into _load_check_data vs. normal save/load. */ if (_sl.action == SLA_LOAD_CHECK) { diff --git a/src/saveload/saveload.h b/src/saveload/saveload.h index f9d191467f..ff18615c26 100644 --- a/src/saveload/saveload.h +++ b/src/saveload/saveload.h @@ -13,6 +13,7 @@ #define SAVELOAD_H #include "../fileio_type.h" +#include "../strings_type.h" #ifdef SIZE_MAX #undef SIZE_MAX @@ -539,6 +540,7 @@ void SlGlobList(const SaveLoadGlobVarList *sldg); void SlArray(void *array, size_t length, VarType conv); void SlObject(void *object, const SaveLoad *sld); bool SlObjectMember(void *object, const SaveLoad *sld); +void NORETURN SlError(StringID string, const char *extra_msg = NULL); void NORETURN SlErrorCorrupt(const char *msg); bool SaveloadCrashWithMissingNewGRFs(); diff --git a/src/saveload/station_sl.cpp b/src/saveload/station_sl.cpp index b0535d9d2c..3304250248 100644 --- a/src/saveload/station_sl.cpp +++ b/src/saveload/station_sl.cpp @@ -284,7 +284,11 @@ static void Load_STNS() /* In old versions, enroute_from used 0xFF as INVALID_STATION */ StationID source = (IsSavegameVersionBefore(7) && _cargo_source == 0xFF) ? INVALID_STATION : _cargo_source; - /* Don't construct the packet with station here, because that'll fail with old savegames */ + /* Make sure we can allocate the CargoPacket. This is safe + * as there can only be ~64k stations and 32 cargos in these + * savegame versions. As the CargoPacketPool has more than + * 16 million entries; it fits by an order of magnitude. */ + assert(CargoPacket::CanAllocateItem()); ge->cargo.Append(new CargoPacket(GB(_waiting_acceptance, 0, 12), _cargo_days, source, _cargo_source_xy, _cargo_source_xy, _cargo_feeder_share)); SB(ge->acceptance_pickup, GoodsEntry::PICKUP, 1, 1); } diff --git a/src/saveload/vehicle_sl.cpp b/src/saveload/vehicle_sl.cpp index d1558d966f..f264c3d106 100644 --- a/src/saveload/vehicle_sl.cpp +++ b/src/saveload/vehicle_sl.cpp @@ -270,6 +270,11 @@ void AfterLoadVehicles(bool part_of_load) if (IsSavegameVersionBefore(105)) { // Pre-105 didn't save an OrderList if (mapping[v->orders.old] == NULL) { /* This adds the whole shared vehicle chain for case b */ + + /* Creating an OrderList here is safe because the number of vehicles + * allowed in these savegames matches the number of OrderLists. As + * such each vehicle can get an OrderList and it will (still) fit. */ + assert(OrderList::CanAllocateItem()); v->orders.list = mapping[v->orders.old] = new OrderList(v->orders.old, v); } else { v->orders.list = mapping[v->orders.old]; @@ -752,7 +757,7 @@ void Load_VEHS() SlObject(v, GetVehicleDescription(vtype)); - if (_cargo_count != 0 && IsCompanyBuildableVehicleType(v)) { + if (_cargo_count != 0 && IsCompanyBuildableVehicleType(v) && CargoPacket::CanAllocateItem()) { /* Don't construct the packet with station here, because that'll fail with old savegames */ CargoPacket *cp = new CargoPacket(_cargo_count, _cargo_days, _cargo_source, _cargo_source_xy, _cargo_loaded_at_xy, _cargo_feeder_share); v->cargo.Append(cp);