aboutsummaryrefslogtreecommitdiff
path: root/engines/sci/engine/kpathing.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'engines/sci/engine/kpathing.cpp')
-rw-r--r--engines/sci/engine/kpathing.cpp64
1 files changed, 48 insertions, 16 deletions
diff --git a/engines/sci/engine/kpathing.cpp b/engines/sci/engine/kpathing.cpp
index 07d0a31f0b..faf966af92 100644
--- a/engines/sci/engine/kpathing.cpp
+++ b/engines/sci/engine/kpathing.cpp
@@ -261,13 +261,7 @@ struct PathfindingState {
int findNearPoint(const Common::Point &p, Polygon *polygon, Common::Point *ret);
};
-
-static Common::Point read_point(SegManager *segMan, reg_t list, int offset) {
- SegmentRef list_r = segMan->dereference(list);
- if (!list_r.isValid() || list_r.skipByte) {
- // If this happens, then the code below will probably go OOB and crash
- error("read_point(): Attempt to dereference invalid pointer %04x:%04x", PRINT_REG(list));
- }
+static Common::Point readPoint(SegmentRef list_r, int offset) {
Common::Point point;
if (list_r.isRaw) {
@@ -350,10 +344,16 @@ static void draw_polygon(EngineState *s, reg_t polygon, int width, int height) {
Common::Point first, prev;
int i;
- prev = first = read_point(segMan, points, 0);
+ SegmentRef pointList = segMan->dereference(points);
+ if (!pointList.isValid() || pointList.skipByte) {
+ warning("draw_polygon: Polygon data pointer is invalid, skipping polygon");
+ return;
+ }
+
+ prev = first = readPoint(pointList, 0);
for (i = 1; i < size; i++) {
- Common::Point point = read_point(segMan, points, i);
+ Common::Point point = readPoint(pointList, i);
draw_line(s, prev, point, type, width, height);
prev = point;
}
@@ -401,12 +401,18 @@ static void print_polygon(SegManager *segMan, reg_t polygon) {
debugN(-1, "%i:", type);
+ SegmentRef pointList = segMan->dereference(points);
+ if (!pointList.isValid() || pointList.skipByte) {
+ warning("print_polygon: Polygon data pointer is invalid, skipping polygon");
+ return;
+ }
+
for (i = 0; i < size; i++) {
- point = read_point(segMan, points, i);
+ point = readPoint(pointList, i);
debugN(-1, " (%i, %i)", point.x, point.y);
}
- point = read_point(segMan, points, 0);
+ point = readPoint(pointList, 0);
debug(" (%i, %i);", point.x, point.y);
}
@@ -1092,7 +1098,22 @@ static Polygon *convert_polygon(EngineState *s, reg_t polygon) {
return NULL;
}
- Polygon *poly = new Polygon(readSelectorValue(segMan, polygon, SELECTOR(type)));
+ SegmentRef pointList = segMan->dereference(points);
+ // Check if the target polygon is still valid. It may have been released
+ // in the meantime (e.g. in LSL6, room 700, when using the elevator).
+ // Refer to bug #3034501.
+ if (!pointList.isValid() || pointList.skipByte) {
+ warning("convert_polygon: Polygon data pointer is invalid, skipping polygon");
+ return NULL;
+ }
+
+ // Make sure that we have enough points
+ if (pointList.maxSize < size * POLY_POINT_SIZE) {
+ warning("convert_polygon: Not enough memory allocated for polygon points. "
+ "Expected %d, got %d. Skipping polygon",
+ size * POLY_POINT_SIZE, pointList.maxSize);
+ return NULL;
+ }
int skip = 0;
@@ -1100,14 +1121,16 @@ static Polygon *convert_polygon(EngineState *s, reg_t polygon) {
// Polygon has 17 points but size is set to 19
if ((size == 19) && g_sci->getGameId() == GID_LSL1) {
if ((s->currentRoomNumber() == 350)
- && (read_point(segMan, points, 18) == Common::Point(108, 137))) {
+ && (readPoint(pointList, 18) == Common::Point(108, 137))) {
debug(1, "Applying fix for broken polygon in lsl1sci, room 350");
size = 17;
}
}
+ Polygon *poly = new Polygon(readSelectorValue(segMan, polygon, SELECTOR(type)));
+
for (i = skip; i < size; i++) {
- Vertex *vertex = new Vertex(read_point(segMan, points, i));
+ Vertex *vertex = new Vertex(readPoint(pointList, i));
poly->vertices.insertHead(vertex);
}
@@ -1163,7 +1186,9 @@ static PathfindingState *convert_polygon_set(EngineState *s, reg_t poly_list, Co
Node *node = s->_segMan->lookupNode(list->first);
while (node) {
- polygon = convert_polygon(s, node->value);
+ // The node value might be null, in which case there's no polygon to parse.
+ // Happens in LB2 floppy - refer to bug #3041232
+ polygon = !node->value.isNull() ? convert_polygon(s, node->value) : NULL;
if (polygon) {
pf_s->polygons.push_back(polygon);
@@ -1402,8 +1427,15 @@ static reg_t output_path(PathfindingState *p, EngineState *s) {
if (DebugMan.isDebugChannelEnabled(kDebugLevelAvoidPath)) {
debug("\nReturning path:");
+
+ SegmentRef outputList = s->_segMan->dereference(output);
+ if (!outputList.isValid() || outputList.skipByte) {
+ warning("output_path: Polygon data pointer is invalid, skipping polygon");
+ return output;
+ }
+
for (int i = 0; i < offset; i++) {
- Common::Point pt = read_point(s->_segMan, output, i);
+ Common::Point pt = readPoint(outputList, i);
debugN(-1, " (%i, %i)", pt.x, pt.y);
}
debug(";\n");