[Scummvm-git-logs] scummvm master -> 20ec3f2d003acb75f7f427d82ee6b059a6ee26c8

sev- noreply at scummvm.org
Thu Aug 6 09:11:23 UTC 2026


This automated email contains information about 4 new commits which have been
pushed to the 'scummvm' repo located at https://api.github.com/repos/scummvm/scummvm .

Summary:
3ecd8d2fb8 MACVENTURE: Fix script sleep opcodes truncating sub-second delays
1069a5f51f MACVENTURE: Fix crash when inventory windows are closed out of order
ad39989b59 MACVENTURE: Fix use-after-free in the inventory window callback
20ec3f2d00 MACVENTURE: Fix crash when dragging objects off the screen edge


Commit: 3ecd8d2fb860238ec19fc073b9ff268c9ee7c6a9
    https://github.com/scummvm/scummvm/commit/3ecd8d2fb860238ec19fc073b9ff268c9ee7c6a9
Author: Ion Andrei Cristian (lecturatul2017 at gmail.com)
Date: 2026-08-06T11:11:17+02:00

Commit Message:
MACVENTURE: Fix script sleep opcodes truncating sub-second delays

Changed paths:
    engines/macventure/script.cpp


diff --git a/engines/macventure/script.cpp b/engines/macventure/script.cpp
index a43e7530972..50558db0f23 100644
--- a/engines/macventure/script.cpp
+++ b/engines/macventure/script.cpp
@@ -1147,7 +1147,8 @@ void ScriptEngine::opd8WIN(EngineState *state, EngineFrame *frame) {
 
 void ScriptEngine::opd9SLEEP(EngineState *state, EngineFrame *frame) {
 	int16 ticks = state->pop();
-	g_system->delayMillis((ticks / 60) * 1000);
+	if (ticks > 0)
+		g_system->delayMillis((ticks * 1000) / 60);
 	_engine->preparedToRun();
 }
 
@@ -1174,7 +1175,8 @@ void ScriptEngine::opdeUPSC(EngineState *state, EngineFrame *frame) {
 
 void ScriptEngine::opdfFMAI(EngineState *state, EngineFrame *frame) {
 	int16 ticks = state->pop();
-	g_system->delayMillis((ticks / 60) * 1000);
+	if (ticks > 0)
+		g_system->delayMillis((ticks * 1000) / 60);
 	_engine->revert();
 }
 


Commit: 1069a5f51ff3e34a40b9480ecd9a21cb53ebf2e8
    https://github.com/scummvm/scummvm/commit/1069a5f51ff3e34a40b9480ecd9a21cb53ebf2e8
Author: Ion Andrei Cristian (lecturatul2017 at gmail.com)
Date: 2026-08-06T11:11:17+02:00

Commit Message:
MACVENTURE: Fix crash when inventory windows are closed out of order

Inventory window references were handed out as the current window count,
and looked up by iterating that same count, which assumes they are always
consecutive. Closing a window that is not the last one breaks that
assumption and makes findObjWindow() ask for a reference that no longer
exists, aborting with "Could not locate the desired window data". Assign
the lowest free reference instead, look the windows up by their actual
references, and drop the object mapping when a window goes away, so that
a stale entry cannot collide with a reused reference.

Changed paths:
    engines/macventure/gui.cpp


diff --git a/engines/macventure/gui.cpp b/engines/macventure/gui.cpp
index 983f7bc492c..967acbc3ca5 100644
--- a/engines/macventure/gui.cpp
+++ b/engines/macventure/gui.cpp
@@ -490,11 +490,21 @@ WindowReference Gui::createInventoryWindow(ObjID objRef) {
 	WindowData newData;
 	GlobalSettings settings = _engine->getGlobalSettings();
 	if (!_objToInvRef.contains(objRef)) {
-		_objToInvRef[objRef] = (WindowReference)(_inventoryWindows.size() + kInventoryStart); // This is a HACK
-		newData.refcon = _objToInvRef[objRef];
-	} else {
-		newData.refcon = _objToInvRef[objRef];
+		WindowReference newRef = kInventoryStart;
+		bool taken = true;
+		while (taken) {
+			taken = false;
+			for (auto &invWindowData : _inventoryWindows) {
+				if (invWindowData.ref == newRef) {
+					taken = true;
+					newRef = (WindowReference)(newRef + 1);
+					break;
+				}
+			}
+		}
+		_objToInvRef[objRef] = newRef;
 	}
+	newData.refcon = _objToInvRef[objRef];
 
 	if (_windowData->back().refcon < 0x80) { // There is already another inventory window
 		newData.bounds = _windowData->back().bounds; // Inventory windows are always last
@@ -1231,11 +1241,11 @@ WindowData &Gui::findWindowData(WindowReference reference) {
 	assert(_windowData);
 
 	Common::List<WindowData>::iterator iter = _windowData->begin();
-	while (iter->refcon != reference && iter != _windowData->end()) {
+	while (iter != _windowData->end() && iter->refcon != reference) {
 		iter++;
 	}
 
-	if (iter->refcon == reference)
+	if (iter != _windowData->end())
 		return *iter;
 
 	error("GUI: Could not locate the desired window data");
@@ -1295,8 +1305,8 @@ WindowReference Gui::findObjWindow(ObjID objID) {
 		}
 	}
 
-	for (uint i = kInventoryStart; i < _inventoryWindows.size() + kInventoryStart; i++) {
-		const WindowData &data = getWindowData((WindowReference)i);
+	for (auto &invWindowData : _inventoryWindows) {
+		const WindowData &data = getWindowData(invWindowData.ref);
 		if (data.objRef == objID) {
 			return data.refcon;
 		}
@@ -1444,6 +1454,14 @@ void Gui::removeInventoryWindow(WindowReference ref) {
 			break;
 		}
 	}
+
+	Common::HashMap<ObjID, WindowReference>::iterator objIt;
+	for (objIt = _objToInvRef.begin(); objIt != _objToInvRef.end(); ++objIt) {
+		if (objIt->_value == ref) {
+			_objToInvRef.erase(objIt);
+			break;
+		}
+	}
 }
 
 


Commit: ad39989b5911819de4a34a422be12c57bc99685a
    https://github.com/scummvm/scummvm/commit/ad39989b5911819de4a34a422be12c57bc99685a
Author: Ion Andrei Cristian (lecturatul2017 at gmail.com)
Date: 2026-08-06T11:11:17+02:00

Commit Message:
MACVENTURE: Fix use-after-free in the inventory window callback

The callback deleted its own data on the close box click, but MacWindow
invokes the callback several times while processing a single event, and
the window itself is only destroyed on the next removeMarked(), so it
kept dispatching events through a dangling pointer. Give the data to the
Gui, which frees it once the window is gone, after clearing the callback.

Changed paths:
    engines/macventure/gui.cpp
    engines/macventure/gui.h


diff --git a/engines/macventure/gui.cpp b/engines/macventure/gui.cpp
index 967acbc3ca5..6e054fde716 100644
--- a/engines/macventure/gui.cpp
+++ b/engines/macventure/gui.cpp
@@ -529,10 +529,11 @@ WindowReference Gui::createInventoryWindow(ObjID objRef) {
 	loadBorders(newWindow, newData.type);
 	newWindow->resizeInner(newData.bounds.width(), newData.bounds.height() - bbs.bottomScrollbarHeight);
 	newWindow->move(newData.bounds.left - bbs.leftOffset, newData.bounds.top - bbs.topOffset);
-	newWindow->setCallback(inventoryWindowCallback, new InventoryCallbackStruct{this, newData.refcon});
+	InventoryCallbackStruct *callbackData = new InventoryCallbackStruct{this, newData.refcon};
+	newWindow->setCallback(inventoryWindowCallback, callbackData);
 	//newWindow->setCloseable(true);
 
-	_inventoryWindows.push_back(InventoryWindowData{newWindow, newData.refcon});
+	_inventoryWindows.push_back(InventoryWindowData{newWindow, newData.refcon, callbackData});
 
 	debugC(1, kMVDebugGUI, "Create new inventory window. Reference: %d", newData.refcon);
 	return newData.refcon;
@@ -1442,6 +1443,8 @@ Common::Point Gui::localizeTravelledDistance(Common::Point point, WindowReferenc
 void Gui::removeInventoryWindow(WindowReference ref) {
 	for (auto &invWinData: _inventoryWindows) {
 		if (invWinData.ref == ref) {
+			invWinData.win->setCallback(nullptr, nullptr);
+			delete invWinData.callbackData;
 			_inventoryWindows.erase(&invWinData);
 			break;
 		}
@@ -1552,12 +1555,8 @@ bool diplomaWindowCallback(Graphics::WindowClick click, Common::Event &event, vo
 
 bool inventoryWindowCallback(Graphics::WindowClick click, Common::Event &event, void *data) {
 	InventoryCallbackStruct *g = (InventoryCallbackStruct *)data;
-	bool res = g->gui->processInventoryEvents(g->ref, click, event);
 
-	if (event.type == Common::EVENT_LBUTTONUP && click == Graphics::kBorderCloseButton)
-		delete g;
-
-	return res;
+	return g->gui->processInventoryEvents(g->ref, click, event);
 }
 
 void menuCommandsCallback(int action, Common::String &text, void *data) {
diff --git a/engines/macventure/gui.h b/engines/macventure/gui.h
index a9a14a9f4ae..def5ecd3985 100644
--- a/engines/macventure/gui.h
+++ b/engines/macventure/gui.h
@@ -58,6 +58,7 @@ class ConsoleText;
 class CommandButton;
 class ImageAsset;
 class Dialog;
+struct InventoryCallbackStruct;
 
 BorderBounds borderBounds(MVWindowType type);
 Graphics::BorderOffsets borderOffsets(MVWindowType type);
@@ -209,6 +210,7 @@ private: // Attributes
 	struct InventoryWindowData {
 		Graphics::MacWindow *win;
 		WindowReference ref;
+		InventoryCallbackStruct *callbackData;
 	};
 	Common::Array<InventoryWindowData> _inventoryWindows;
 	Common::HashMap<ObjID, WindowReference> _objToInvRef;


Commit: 20ec3f2d003acb75f7f427d82ee6b059a6ee26c8
    https://github.com/scummvm/scummvm/commit/20ec3f2d003acb75f7f427d82ee6b059a6ee26c8
Author: Ion Andrei Cristian (lecturatul2017 at gmail.com)
Date: 2026-08-06T11:11:17+02:00

Commit Message:
MACVENTURE: Fix crash when dragging objects off the screen edge

Dragging an object to the very bottom or right edge left it with a zero
sized surface, whose base pointer is null, tripping an assertion in
copyRectToScreen(). Dragging it past the edge was worse: the clamping was
done in unsigned arithmetic, so the subtraction wrapped around and asked
for a huge surface. Clamp with signed math and skip the object when it
ends up with nothing visible.

Changed paths:
    engines/macventure/gui.cpp


diff --git a/engines/macventure/gui.cpp b/engines/macventure/gui.cpp
index 6e054fde716..699edd390dc 100644
--- a/engines/macventure/gui.cpp
+++ b/engines/macventure/gui.cpp
@@ -967,15 +967,19 @@ void Gui::drawDraggedObjects() {
 			ImageAsset *asset = _assets[_draggedObjects[i].id];
 
 			// In case of overflow from the right/top
-			uint w = asset->getWidth() + MIN((int16)0, _draggedObjects[i].pos.x);
-			uint h = asset->getHeight() + MIN((int16)0, _draggedObjects[i].pos.y);
+			int w = asset->getWidth() + MIN((int16)0, _draggedObjects[i].pos.x);
+			int h = asset->getHeight() + MIN((int16)0, _draggedObjects[i].pos.y);
 
 			// In case of overflow from the bottom/left
 			if (_draggedObjects[i].pos.x > 0 && _draggedObjects[i].pos.x + w > kScreenWidth) {
-				w = kScreenWidth - _draggedObjects[i].pos.x;
+				w = MAX(0, kScreenWidth - _draggedObjects[i].pos.x);
 			}
 			if (_draggedObjects[i].pos.y > 0 && _draggedObjects[i].pos.y + h > kScreenHeight) {
-				h = kScreenHeight - _draggedObjects[i].pos.y;
+				h = MAX(0, kScreenHeight - _draggedObjects[i].pos.y);
+			}
+
+			if (w <= 0 || h <= 0) {
+				continue;
 			}
 
 			Common::Point target = _draggedObjects[i].pos;




More information about the Scummvm-git-logs mailing list