(svn r11122) -Fix [FS#1234]: crash when building a NewGRF vehicle when the articulated build vehicle callback returneed a different value for the purchase window than the normal build. Thanks for Dalestan and _minime_ for pointers to possible causes.
authorrubidium
Mon, 17 Sep 2007 04:23:03 +0000
changeset 8091 f24d360b6ba1
parent 8090 454ea60f6414
child 8092 c8d04c7da7e9
(svn r11122) -Fix [FS#1234]: crash when building a NewGRF vehicle when the articulated build vehicle callback returneed a different value for the purchase window than the normal build. Thanks for Dalestan and _minime_ for pointers to possible causes.
src/articulated_vehicles.cpp
src/articulated_vehicles.h
src/build_vehicle_gui.cpp
src/roadveh_cmd.cpp
src/train_cmd.cpp
--- a/src/articulated_vehicles.cpp	Sun Sep 16 21:34:50 2007 +0000
+++ b/src/articulated_vehicles.cpp	Mon Sep 17 04:23:03 2007 +0000
@@ -15,16 +15,24 @@
 #include "newgrf_engine.h"
 
 
-uint CountArticulatedParts(EngineID engine_type)
+uint CountArticulatedParts(EngineID engine_type, bool purchase_window)
 {
 	if (!HASBIT(EngInfo(engine_type)->callbackmask, CBM_ARTIC_ENGINE)) return 0;
 
+	Vehicle *v = NULL;;
+	if (!purchase_window) {
+		v = new InvalidVehicle();
+		v->engine_type = engine_type;
+	}
+
 	uint i;
 	for (i = 1; i < MAX_UVALUE(EngineID); i++) {
-		uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine_type, NULL);
+		uint16 callback = GetVehicleCallback(CBID_VEHICLE_ARTIC_ENGINE, i, 0, engine_type, v);
 		if (callback == CALLBACK_FAILED || callback == 0xFF) break;
 	}
 
+	delete v;
+
 	return i - 1;
 }
 
@@ -42,7 +50,6 @@
 		/* Attempt to use pre-allocated vehicles until they run out. This can happen
 		 * if the callback returns different values depending on the cargo type. */
 		u->SetNext(vl[i]);
-		if (u->Next() == NULL) u->SetNext(new InvalidVehicle());
 		if (u->Next() == NULL) return;
 
 		Vehicle *previous = u;
--- a/src/articulated_vehicles.h	Sun Sep 16 21:34:50 2007 +0000
+++ b/src/articulated_vehicles.h	Mon Sep 17 04:23:03 2007 +0000
@@ -5,7 +5,7 @@
 #ifndef ARTICULATED_VEHICLES_H
 #define ARTICULATED_VEHICLES_H
 
-uint CountArticulatedParts(EngineID engine_type);
+uint CountArticulatedParts(EngineID engine_type, bool purchase_window);
 void AddArticulatedParts(Vehicle **vl, VehicleType type);
 
 #endif /* ARTICULATED_VEHICLES_H */
--- a/src/build_vehicle_gui.cpp	Sun Sep 16 21:34:50 2007 +0000
+++ b/src/build_vehicle_gui.cpp	Mon Sep 17 04:23:03 2007 +0000
@@ -621,7 +621,7 @@
 				int multihead = (rvi->railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
 
 				SetDParam(0, rvi->cargo_type);
-				SetDParam(1, (capacity * (CountArticulatedParts(engine_number) + 1)) << multihead);
+				SetDParam(1, (capacity * (CountArticulatedParts(engine_number, true) + 1)) << multihead);
 				SetDParam(2, refitable ? STR_9842_REFITTABLE : STR_EMPTY);
 			}
 			DrawString(x, y, STR_PURCHASE_INFO_CAPACITY, 0);
--- a/src/roadveh_cmd.cpp	Sun Sep 16 21:34:50 2007 +0000
+++ b/src/roadveh_cmd.cpp	Mon Sep 17 04:23:03 2007 +0000
@@ -179,11 +179,11 @@
 
 	if (HASBIT(GetRoadTypes(tile), ROADTYPE_TRAM) != HASBIT(EngInfo(p1)->misc_flags, EF_ROAD_TRAM)) return_cmd_error(STR_DEPOT_WRONG_DEPOT_TYPE);
 
-	uint num_vehicles = 1 + CountArticulatedParts(p1);
+	uint num_vehicles = 1 + CountArticulatedParts(p1, false);
 
-	/* Allow for the front and the articulated parts. */
-	Vehicle **vl = (Vehicle**)alloca(sizeof(*vl) * num_vehicles);
-	memset(vl, 0, sizeof(*vl) * num_vehicles);
+	/* Allow for the front and the articulated parts, plus one to "terminate" the list. */
+	Vehicle **vl = (Vehicle**)alloca(sizeof(*vl) * (num_vehicles + 1));
+	memset(vl, 0, sizeof(*vl) * (num_vehicles + 1));
 
 	if (!Vehicle::AllocateList(vl, num_vehicles)) {
 		return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
--- a/src/train_cmd.cpp	Sun Sep 16 21:34:50 2007 +0000
+++ b/src/train_cmd.cpp	Mon Sep 17 04:23:03 2007 +0000
@@ -514,12 +514,12 @@
 	const RailVehicleInfo *rvi = RailVehInfo(engine);
 	CommandCost value((GetEngineProperty(engine, 0x17, rvi->base_cost) * _price.build_railwagon) >> 8);
 
-	uint num_vehicles = 1 + CountArticulatedParts(engine);
+	uint num_vehicles = 1 + CountArticulatedParts(engine, false);
 
 	if (!(flags & DC_QUERY_COST)) {
-		/* Allow for the wagon and the articulated parts. */
-		Vehicle **vl = (Vehicle**)alloca(sizeof(*vl) * num_vehicles);
-		memset(vl, 0, sizeof(*vl) * num_vehicles);
+		/* Allow for the wagon and the articulated parts, plus one to "terminate" the list. */
+		Vehicle **vl = (Vehicle**)alloca(sizeof(*vl) * (num_vehicles + 1));
+		memset(vl, 0, sizeof(*vl) * (num_vehicles + 1));
 
 		if (!Vehicle::AllocateList(vl, num_vehicles))
 			return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);
@@ -682,12 +682,12 @@
 
 	uint num_vehicles =
 		(rvi->railveh_type == RAILVEH_MULTIHEAD ? 2 : 1) +
-		CountArticulatedParts(p1);
+		CountArticulatedParts(p1, false);
 
 	if (!(flags & DC_QUERY_COST)) {
-		/* Allow for the dual-heads and the articulated parts. */
-		Vehicle **vl = (Vehicle**)alloca(sizeof(*vl) * num_vehicles);
-		memset(vl, 0, sizeof(*vl) * num_vehicles);
+		/* Allow for the dual-heads and the articulated parts, plus one to "terminate" the list. */
+		Vehicle **vl = (Vehicle**)alloca(sizeof(*vl) * (num_vehicles + 1));
+		memset(vl, 0, sizeof(*vl) * (num_vehicles + 1));
 
 		if (!Vehicle::AllocateList(vl, num_vehicles))
 			return_cmd_error(STR_00E1_TOO_MANY_VEHICLES_IN_GAME);