[Scummvm-git-logs] scummvm master -> 4b556154520bfc318b23619bb5f6a7b468270a73

neuromancer noreply at scummvm.org
Sun Nov 2 18:34:31 UTC 2025


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

Summary:
3caaca94f8 PRIVATE: Fix memory leak on cursor change
4b7ec623b6 PRIVATE: Use local InstallShieldV3 objects
6e5dc8d941 PRIVATE: Fix memory leaks when loading Windows cursors
f805443d73 PRIVATE: Fix memory leaks in PrivateEngine
e3bb88f880 PRIVATE: Fix memory leak when decoding a remapped image
dc0079a6b7 PRIVATE: Fix memory leak when loading inventory
dc9faaee98 PRIVATE: Fix memory leak in SettingMaps
14c50f6e9d PRIVATE: Fix leaked Graphics::Surfaces when clearing masks
2268f80337 PRIVATE: Fix memory leak when setting timer
e7ff9e9044 PRIVATE: Fixed memory leak in fCRect
866d676616 PRIVATE: Fix memory leak in parser
28871bbd64 PRIVATE: Fix memory leaks in SymbolMaps and lexer
b3fd1bb2f3 PRIVATE: Fix memory leak when restarting game
4b55615452 PRIVATE: Fix loading cursors in Windows demos


Commit: 3caaca94f877c842bc034fe89969e8f29030e70a
    https://github.com/scummvm/scummvm/commit/3caaca94f877c842bc034fe89969e8f29030e70a
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-02T19:34:22+01:00

Commit Message:
PRIVATE: Fix memory leak on cursor change

Changed paths:
    engines/private/cursors.cpp
    engines/private/private.cpp
    engines/private/private.h


diff --git a/engines/private/cursors.cpp b/engines/private/cursors.cpp
index 973888bd812..3fcefdf0eb7 100644
--- a/engines/private/cursors.cpp
+++ b/engines/private/cursors.cpp
@@ -43,6 +43,8 @@ struct CursorEntry {
 };
 
 void PrivateEngine::loadCursors() {
+	_defaultCursor = Graphics::makeDefaultWinCursor();
+
 	if (_platform == Common::kPlatformWindows) {
 		const CursorEntry cursorIDReference[] = {
 			{ "kTurnLeft",  "k1", 23 },
@@ -138,7 +140,7 @@ void PrivateEngine::changeCursor(const Common::String &cursor) {
 	}
 
 	if (cursor == "default") {
-		CursorMan.replaceCursor(Graphics::makeDefaultWinCursor());
+		CursorMan.replaceCursor(_defaultCursor);
 	} else {
 		for (uint i = 0; i < _cursors.size(); i++) {
 			if (_cursors[i].name == cursor || _cursors[i].aname == cursor) {
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index 62c3f836683..496e5ff92b6 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -54,6 +54,7 @@ PrivateEngine::PrivateEngine(OSystem *syst, const ADGameDescription *gd)
 	  _compositeSurface(nullptr), _transparentColor(0), _frameImage(nullptr),
 	  _framePalette(nullptr), _maxNumberClicks(0), _sirenWarning(0), 
 	  _subtitles(nullptr), _sfxSubtitles(false), _useSubtitles(false),
+	  _defaultCursor(nullptr),
 	  _screenW(640), _screenH(480) {
 	_rnd = new Common::RandomSource("private");
 
@@ -129,6 +130,7 @@ PrivateEngine::~PrivateEngine() {
 	delete Gen::g_vm;
 	delete Settings::g_setts;
 
+	delete _defaultCursor;
 	for (uint i = 0; i < _cursors.size(); i++) {
 		if (_cursors[i].winCursorGroup == nullptr) {
 			delete _cursors[i].cursor;
diff --git a/engines/private/private.h b/engines/private/private.h
index 81f4e66a8e1..dc52669ad9d 100644
--- a/engines/private/private.h
+++ b/engines/private/private.h
@@ -236,6 +236,7 @@ public:
 	void drawScreenFrame(const byte *videoPalette);
 
 	// Cursors
+	Graphics::Cursor *_defaultCursor;
 	Common::Array<CursorInfo> _cursors;
 	Common::String _currentCursor;
 	void changeCursor(const Common::String &);


Commit: 4b7ec623b65956bcc92a90eda14e8cce2d1184c6
    https://github.com/scummvm/scummvm/commit/4b7ec623b65956bcc92a90eda14e8cce2d1184c6
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-02T19:34:22+01:00

Commit Message:
PRIVATE: Use local InstallShieldV3 objects

Changed paths:
    engines/private/cursors.cpp
    engines/private/private.cpp
    engines/private/private.h


diff --git a/engines/private/cursors.cpp b/engines/private/cursors.cpp
index 3fcefdf0eb7..e6842651678 100644
--- a/engines/private/cursors.cpp
+++ b/engines/private/cursors.cpp
@@ -22,6 +22,8 @@
 #include "common/rect.h"
 #include "graphics/cursorman.h"
 
+#include "common/compression/installshieldv3_archive.h"
+
 #include "common/formats/winexe_ne.h"
 #include "common/formats/winexe_pe.h"
 
@@ -59,11 +61,12 @@ void PrivateEngine::loadCursors() {
 
 		Common::WinResources *exe = nullptr;
 		Common::ArchiveMemberList members;
-		if (_installerArchive.open("SUPPORT/PVTEYE.Z"))
+		Common::InstallShieldV3 installerArchive;
+		if (installerArchive.open("SUPPORT/PVTEYE.Z"))
 			if (_language == Common::JA_JPN)
-				exe = Common::WinResources::createFromEXE(_installerArchive.createReadStreamForMember("PvteyeJ.EXE"));
+				exe = Common::WinResources::createFromEXE(installerArchive.createReadStreamForMember("PvteyeJ.EXE"));
 			else
-				exe = Common::WinResources::createFromEXE(_installerArchive.createReadStreamForMember("PVTEYE.EXE"));
+				exe = Common::WinResources::createFromEXE(installerArchive.createReadStreamForMember("PVTEYE.EXE"));
 		else  {
 			Common::File file;
 			if (!file.open("SUPPORT/PVTEYE.EX_")) {
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index 496e5ff92b6..f4743a084db 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -22,6 +22,7 @@
 #include "audio/audiostream.h"
 #include "audio/decoders/wave.h"
 #include "common/archive.h"
+#include "common/compression/installshieldv3_archive.h"
 #include "common/config-manager.h"
 #include "common/debug-channels.h"
 #include "common/debug.h"
@@ -175,27 +176,28 @@ Common::SeekableReadStream *PrivateEngine::loadAssets() {
 			return file2;
 	}
 
-	if (!_installerArchive.open("SUPPORT/ASSETS.Z"))
+	Common::InstallShieldV3 installerArchive;
+	if (!installerArchive.open("SUPPORT/ASSETS.Z"))
 		error("Failed to open SUPPORT/ASSETS.Z");
 	// if the full game is used
 	if (!isDemo()) {
-		if (_installerArchive.hasFile("GAME.DAT"))
-			return _installerArchive.createReadStreamForMember("GAME.DAT");
-		if (_installerArchive.hasFile("GAME.WIN"))
-			return _installerArchive.createReadStreamForMember("GAME.WIN");
+		if (installerArchive.hasFile("GAME.DAT"))
+			return installerArchive.createReadStreamForMember("GAME.DAT");
+		if (installerArchive.hasFile("GAME.WIN"))
+			return installerArchive.createReadStreamForMember("GAME.WIN");
 		error("Unknown version");
 		return nullptr;
 	}
 
 	// if the demo from archive.org is used
-	if (_installerArchive.hasFile("GAME.TXT"))
-		return _installerArchive.createReadStreamForMember("GAME.TXT");
+	if (installerArchive.hasFile("GAME.TXT"))
+		return installerArchive.createReadStreamForMember("GAME.TXT");
 
 	// if the demo from the full retail CDROM is used
-	if (_installerArchive.hasFile("DEMOGAME.DAT"))
-		return _installerArchive.createReadStreamForMember("DEMOGAME.DAT");
-	if (_installerArchive.hasFile("DEMOGAME.WIN"))
-		return _installerArchive.createReadStreamForMember("DEMOGAME.WIN");
+	if (installerArchive.hasFile("DEMOGAME.DAT"))
+		return installerArchive.createReadStreamForMember("DEMOGAME.DAT");
+	if (installerArchive.hasFile("DEMOGAME.WIN"))
+		return installerArchive.createReadStreamForMember("DEMOGAME.WIN");
 
 	error("Unknown version");
 	return nullptr;
diff --git a/engines/private/private.h b/engines/private/private.h
index dc52669ad9d..551471444ea 100644
--- a/engines/private/private.h
+++ b/engines/private/private.h
@@ -22,7 +22,6 @@
 #ifndef PRIVATE_H
 #define PRIVATE_H
 
-#include "common/compression/installshieldv3_archive.h"
 #include "common/random.h"
 #include "common/serializer.h"
 #include "engines/engine.h"
@@ -178,7 +177,6 @@ public:
 	Audio::SoundHandle _bgSoundHandle;
 	Video::SmackerDecoder *_videoDecoder;
 	Video::SmackerDecoder *_pausedVideo;
-	Common::InstallShieldV3 _installerArchive;
 
 	Common::Error run() override;
 	void restartGame();


Commit: 6e5dc8d941aa5a28524a8de187ee4c7253742145
    https://github.com/scummvm/scummvm/commit/6e5dc8d941aa5a28524a8de187ee4c7253742145
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-02T19:34:22+01:00

Commit Message:
PRIVATE: Fix memory leaks when loading Windows cursors

Changed paths:
    engines/private/cursors.cpp


diff --git a/engines/private/cursors.cpp b/engines/private/cursors.cpp
index e6842651678..9e0adfbc89c 100644
--- a/engines/private/cursors.cpp
+++ b/engines/private/cursors.cpp
@@ -60,21 +60,24 @@ void PrivateEngine::loadCursors() {
 		};
 
 		Common::WinResources *exe = nullptr;
+		Common::SeekableReadStream *exeStream = nullptr;
 		Common::ArchiveMemberList members;
 		Common::InstallShieldV3 installerArchive;
-		if (installerArchive.open("SUPPORT/PVTEYE.Z"))
-			if (_language == Common::JA_JPN)
-				exe = Common::WinResources::createFromEXE(installerArchive.createReadStreamForMember("PvteyeJ.EXE"));
-			else
-				exe = Common::WinResources::createFromEXE(installerArchive.createReadStreamForMember("PVTEYE.EXE"));
-		else  {
-			Common::File file;
-			if (!file.open("SUPPORT/PVTEYE.EX_")) {
+		if (installerArchive.open("SUPPORT/PVTEYE.Z")) {
+			const char *exeName = (_language == Common::JA_JPN) ? "PvteyeJ.EXE" : "PVTEYE.EXE";
+			exeStream = installerArchive.createReadStreamForMember(exeName);
+			if (exeStream == nullptr) {
+				error("%s not found", exeName);
+			}
+		} else {
+			Common::File *file = new Common::File();
+			if (!file->open("SUPPORT/PVTEYE.EX_")) {
 				error("PVTEYE.EX_ not found");
 			}
-			exe = Common::WinResources::createFromEXE(file.readStream(file.size()));
+			exeStream = file;
 		}
 
+		exe = Common::WinResources::createFromEXE(exeStream);
 		if (exe == nullptr) {
 			error("Executable not found");
 		}
@@ -97,6 +100,9 @@ void PrivateEngine::loadCursors() {
 				entry++;
 			}
 		}
+
+		delete exe;
+		delete exeStream;
 	} else {
 		const CursorEntry cursorIDReference[] = {
 			{ "kTurnLeft",  "k1", 133 },


Commit: f805443d7352139706113958216a58ae9d816faa
    https://github.com/scummvm/scummvm/commit/f805443d7352139706113958216a58ae9d816faa
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-02T19:34:22+01:00

Commit Message:
PRIVATE: Fix memory leaks in PrivateEngine

Changed paths:
    engines/private/private.cpp


diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index f4743a084db..97e007d9482 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -124,9 +124,24 @@ PrivateEngine::PrivateEngine(OSystem *syst, const ADGameDescription *gd)
 }
 
 PrivateEngine::~PrivateEngine() {
-	// Dispose your resources here
-	delete _frameImage;
+	if (_videoDecoder != _pausedVideo) {
+		delete _pausedVideo;
+	}
+	delete _videoDecoder;
+
+	delete _compositeSurface;
+	if (_frameImage != nullptr) {
+		_frameImage->free();
+		delete _frameImage;
+	}
+	if (_mframeImage != nullptr) {
+		_mframeImage->free();
+		delete _mframeImage;
+	}
+	free(_framePalette);
+
 	delete _rnd;
+	delete _image;
 
 	delete Gen::g_vm;
 	delete Settings::g_setts;


Commit: e3bb88f880bba3111e4e7af93503a74915dd08b0
    https://github.com/scummvm/scummvm/commit/e3bb88f880bba3111e4e7af93503a74915dd08b0
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-02T19:34:22+01:00

Commit Message:
PRIVATE: Fix memory leak when decoding a remapped image

Changed paths:
    engines/private/metaengine.cpp
    engines/private/private.cpp
    engines/private/private.h


diff --git a/engines/private/metaengine.cpp b/engines/private/metaengine.cpp
index c12475a440c..07276a53dd7 100644
--- a/engines/private/metaengine.cpp
+++ b/engines/private/metaengine.cpp
@@ -67,10 +67,14 @@ Common::Error PrivateMetaEngine::createInstance(OSystem *syst, Engine **engine,
 
 void PrivateMetaEngine::getSavegameThumbnail(Graphics::Surface &thumb) {
 	byte *palette;
-	Graphics::Surface *vs = Private::g_private->decodeImage(Private::g_private->_nextVS, &palette);
+	bool isNewPalette;
+	Graphics::Surface *vs = Private::g_private->decodeImage(Private::g_private->_nextVS, &palette, &isNewPalette);
 	::createThumbnail(&thumb, (const uint8 *)vs->getPixels(), vs->w, vs->h, palette);
 	vs->free();
 	delete vs;
+	if (isNewPalette) {
+		free(palette);
+	}
 }
 
 Common::KeymapArray PrivateMetaEngine::initKeymaps(const char *target) const {
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index 97e007d9482..5712f805734 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -278,18 +278,28 @@ Common::Error PrivateEngine::run() {
 
 	// Load the game frame once
 	byte *palette;
-	_frameImage = decodeImage(_framePath, nullptr);
-	_mframeImage = decodeImage(_framePath, &palette);
+	bool isNewPalette;
+	_frameImage = decodeImage(_framePath, nullptr, nullptr);
+	_mframeImage = decodeImage(_framePath, &palette, &isNewPalette);
 
 	_framePalette = (byte *) malloc(3*256);
 	memcpy(_framePalette, palette, 3*256);
+	if (isNewPalette) {
+		free(palette);
+		palette = nullptr;
+	}
 
 	byte *initialPalette;
-	Graphics::Surface *surf = decodeImage("inface/general/inface1.bmp", &initialPalette);
+	bool isNewInitialPalette;
+	Graphics::Surface *surf = decodeImage("inface/general/inface1.bmp", &initialPalette, &isNewInitialPalette);
 	_compositeSurface->setPalette(initialPalette, 0, 256);
 	surf->free();
 	delete surf;
 	_image->destroy();
+	if (isNewInitialPalette) {
+		free(initialPalette);
+		initialPalette = nullptr;
+	}
 
 	// Main event loop
 	Common::Event event;
@@ -1594,7 +1604,7 @@ void PrivateEngine::stopSound(bool all) {
 	}
 }
 
-Graphics::Surface *PrivateEngine::decodeImage(const Common::String &name, byte **palette) {
+Graphics::Surface *PrivateEngine::decodeImage(const Common::String &name, byte **palette, bool *isNewPalette) {
 	debugC(1, kPrivateDebugFunction, "%s(%s)", __FUNCTION__, name.c_str());
 	Common::Path path = convertPath(name);
 	Common::ScopedPtr<Common::SeekableReadStream> file(Common::MacResManager::openFileOrDataFork(path));
@@ -1615,13 +1625,26 @@ Graphics::Surface *PrivateEngine::decodeImage(const Common::String &name, byte *
 		g_system->getPaletteManager()->grabPalette(currentPalette, 0, 256);
 		newImage = oldImage->convertTo(_pixelFormat, currentPalette);
 		remapImage(ncolors, oldImage, oldPalette, newImage, currentPalette);
+		if (palette != nullptr) {
+			*palette = currentPalette;
+			if (isNewPalette != nullptr) {
+				*isNewPalette = true;
+			}
+		} else {
+			free(currentPalette);
+			if (isNewPalette != nullptr) {
+				*isNewPalette = false;
+			}
+		}
 	} else {
 		currentPalette = const_cast<byte *>(oldPalette);
 		newImage = oldImage->convertTo(_pixelFormat, currentPalette);
-	}
-
-	if (palette != nullptr) {
-		*palette = currentPalette;
+		if (palette != nullptr) {
+			*palette = currentPalette;
+		}
+		if (isNewPalette != nullptr) {
+			*isNewPalette = false;
+		}
 	}
 
 	return newImage;
@@ -1670,13 +1693,17 @@ void PrivateEngine::remapImage(uint16 ncolors, const Graphics::Surface *oldImage
 void PrivateEngine::loadImage(const Common::String &name, int x, int y) {
 	debugC(1, kPrivateDebugFunction, "%s(%s,%d,%d)", __FUNCTION__, name.c_str(), x, y);
 	byte *palette;
-	Graphics::Surface *surf = decodeImage(name, &palette);
+	bool isNewPalette;
+	Graphics::Surface *surf = decodeImage(name, &palette, &isNewPalette);
 	_compositeSurface->setPalette(palette, 0, 256);
 	_compositeSurface->setTransparentColor(_transparentColor);
 	_compositeSurface->transBlitFrom(*surf, _origin + Common::Point(x, y), _transparentColor);
 	surf->free();
 	delete surf;
 	_image->destroy();
+	if (isNewPalette) {
+		free(palette);
+	}
 }
 
 void PrivateEngine::fillRect(uint32 color, Common::Rect rect) {
@@ -1697,7 +1724,8 @@ Graphics::Surface *PrivateEngine::loadMask(const Common::String &name, int x, in
 	surf->create(_screenW, _screenH, _pixelFormat);
 	surf->fillRect(_screenRect, _transparentColor);
 	byte *palette;
-	Graphics::Surface *csurf = decodeImage(name, &palette);
+	bool isNewPalette;
+	Graphics::Surface *csurf = decodeImage(name, &palette, &isNewPalette);
 
 	uint32 hdiff = 0;
 	uint32 wdiff = 0;
@@ -1720,6 +1748,10 @@ Graphics::Surface *PrivateEngine::loadMask(const Common::String &name, int x, in
 	delete csurf;
 	_image->destroy();
 
+	if (isNewPalette) {
+		free(palette);
+	}
+
 	return surf;
 }
 
diff --git a/engines/private/private.h b/engines/private/private.h
index 551471444ea..84f7e01c992 100644
--- a/engines/private/private.h
+++ b/engines/private/private.h
@@ -227,7 +227,7 @@ public:
 	bool _useSubtitles;
 	bool _sfxSubtitles;
 
-	Graphics::Surface *decodeImage(const Common::String &file, byte **palette);
+	Graphics::Surface *decodeImage(const Common::String &file, byte **palette, bool *isNewPalette);
 	//byte *decodePalette(const Common::String &name);
 	void remapImage(uint16 ncolors, const Graphics::Surface *oldImage, const byte *oldPalette, Graphics::Surface *newImage, const byte *currentPalette);
 	void loadImage(const Common::String &file, int x, int y);


Commit: dc0079a6b7e9a9bfd461ef6439996cfb46f7af49
    https://github.com/scummvm/scummvm/commit/dc0079a6b7e9a9bfd461ef6439996cfb46f7af49
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-02T19:34:22+01:00

Commit Message:
PRIVATE: Fix memory leak when loading inventory

Changed paths:
    engines/private/private.cpp


diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index 5712f805734..911a48ab663 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -1881,6 +1881,7 @@ void PrivateEngine::loadInventory(uint32 x, const Common::Rect &r1, const Common
 	for (NameList::const_iterator it = inventory.begin(); it != inventory.end(); ++it) {
 		offset = offset + 22;
 		Graphics::Surface *surface = loadMask(*it, r1.left, r1.top + offset, true);
+		surface->free();
 		delete surface;
 	}
 }


Commit: dc9faaee988d3cfbbac0ce3771bc258b24d9d64e
    https://github.com/scummvm/scummvm/commit/dc9faaee988d3cfbbac0ce3771bc258b24d9d64e
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-02T19:34:22+01:00

Commit Message:
PRIVATE: Fix memory leak in SettingMaps

Changed paths:
    engines/private/code.cpp
    engines/private/grammar.h


diff --git a/engines/private/code.cpp b/engines/private/code.cpp
index 9713d0515e7..a66d787c3bb 100644
--- a/engines/private/code.cpp
+++ b/engines/private/code.cpp
@@ -64,9 +64,20 @@ using namespace Gen;
 
 SettingMaps *g_setts;
 
+SettingMaps::SettingMaps() :
+	_setting(nullptr) {
+}
+
+SettingMaps::~SettingMaps() {
+	for (uint i = 0; i < _settings.size(); i++) {
+		free(_settings[i]);
+	}
+}
+
 /* initialize setting for code generation */
 void SettingMaps::init() {
 	_setting = (Setting *)malloc(sizeof(Setting));
+	_settings.push_back(_setting);
 	memset((void *)_setting, 0, sizeof(Setting));
 
 	g_vm->_prog = (Inst *)&_setting->prog;
diff --git a/engines/private/grammar.h b/engines/private/grammar.h
index 845f038f415..bc0b2d7b8da 100644
--- a/engines/private/grammar.h
+++ b/engines/private/grammar.h
@@ -71,12 +71,18 @@ typedef Common::HashMap<Common::String, Setting *> SettingMap;
 
 class SettingMaps {
 public:
+	SettingMaps();
+	~SettingMaps();
+
 	Setting *_setting;
 	SettingMap _map;
 
 	void init();
 	void save(const char *);
 	void load(const Common::String &);
+
+private:
+	Common::Array<Setting *> _settings;
 };
 
 extern SettingMaps *g_setts;


Commit: 14c50f6e9dfa42dd4a340fee29af7dbbf219e43d
    https://github.com/scummvm/scummvm/commit/14c50f6e9dfa42dd4a340fee29af7dbbf219e43d
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-02T19:34:22+01:00

Commit Message:
PRIVATE: Fix leaked Graphics::Surfaces when clearing masks

Changed paths:
    engines/private/funcs.cpp
    engines/private/private.cpp


diff --git a/engines/private/funcs.cpp b/engines/private/funcs.cpp
index 9e0b1775944..96f2e19f6b2 100644
--- a/engines/private/funcs.cpp
+++ b/engines/private/funcs.cpp
@@ -195,9 +195,6 @@ static void fLoadGame(ArgArray args) {
 	m.nextSetting = "";
 	m.flag1 = nullptr;
 	m.flag2 = nullptr;
-	if (g_private->_loadGameMask.surf)
-		g_private->_loadGameMask.surf->free();
-	delete g_private->_loadGameMask.surf;
 	g_private->_loadGameMask = m;
 	g_private->_masks.push_front(m);
 }
@@ -211,9 +208,6 @@ static void fSaveGame(ArgArray args) {
 	m.nextSetting = "";
 	m.flag1 = nullptr;
 	m.flag2 = nullptr;
-	if (g_private->_saveGameMask.surf)
-		g_private->_saveGameMask.surf->free();
-	delete g_private->_saveGameMask.surf;
 	g_private->_saveGameMask = m;
 	g_private->_masks.push_front(m);
 }
@@ -743,9 +737,6 @@ static void fSoundArea(ArgArray args) {
 		m.nextSetting = "";
 		m.flag1 = nullptr;
 		m.flag2 = nullptr;
-		if (g_private->_AMRadioArea.surf)
-			g_private->_AMRadioArea.surf->free();
-		delete g_private->_AMRadioArea.surf;
 		g_private->_AMRadioArea = m;
 		g_private->_masks.push_front(m);
 	} else if (n == "kPoliceRadio") {
@@ -754,9 +745,6 @@ static void fSoundArea(ArgArray args) {
 		m.nextSetting = "";
 		m.flag1 = nullptr;
 		m.flag2 = nullptr;
-		if (g_private->_policeRadioArea.surf)
-			g_private->_policeRadioArea.surf->free();
-		delete g_private->_policeRadioArea.surf;
 		g_private->_policeRadioArea = m;
 		g_private->_masks.push_front(m);
 	} else if (n == "kPhone") {
@@ -765,9 +753,6 @@ static void fSoundArea(ArgArray args) {
 		m.nextSetting = "";
 		m.flag1 = nullptr;
 		m.flag2 = nullptr;
-		if (g_private->_phoneArea.surf)
-			g_private->_phoneArea.surf->free();
-		delete g_private->_phoneArea.surf;
 		g_private->_phoneArea = m;
 		g_private->_masks.push_front(m);
 	} else
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index 911a48ab663..6d9dc8f019c 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -153,6 +153,14 @@ PrivateEngine::~PrivateEngine() {
 		}
 		delete _cursors[i].winCursorGroup;
 	}
+
+	for (MaskList::const_iterator it = _masks.begin(); it != _masks.end(); ++it) {
+		const MaskInfo &m = *it;
+		if (m.surf != nullptr) {
+			m.surf->free();
+			delete m.surf;
+		}
+	}
 }
 
 void PrivateEngine::initializePath(const Common::FSNode &gamePath) {
@@ -478,60 +486,34 @@ void PrivateEngine::initFuncs() {
 }
 
 void PrivateEngine::clearAreas() {
+	for (MaskList::const_iterator it = _masks.begin(); it != _masks.end(); ++it) {
+		const MaskInfo &m = *it;
+		if (m.surf != nullptr) {
+			m.surf->free();
+			delete m.surf;
+		}
+	}
+
 	_exits.clear();
 	_masks.clear();
 	_locationMasks.clear();
 	_memoryMasks.clear();
 
-	if (_loadGameMask.surf)
-		_loadGameMask.surf->free();
-	delete _loadGameMask.surf;
 	_loadGameMask.clear();
-
-	if (_saveGameMask.surf)
-		_saveGameMask.surf->free();
-	delete _saveGameMask.surf;
 	_saveGameMask.clear();
-
-	if (_policeRadioArea.surf)
-		_policeRadioArea.surf->free();
-	delete _policeRadioArea.surf;
 	_policeRadioArea.clear();
-
-	if (_AMRadioArea.surf)
-		_AMRadioArea.surf->free();
-	delete _AMRadioArea.surf;
 	_AMRadioArea.clear();
-
-	if (_phoneArea.surf)
-		_phoneArea.surf->free();
-	delete _phoneArea.surf;
 	_phoneArea.clear();
-
-	if (_dossierNextSuspectMask.surf)
-		_dossierNextSuspectMask.surf->free();
-	delete _dossierNextSuspectMask.surf;
 	_dossierNextSuspectMask.clear();
-
-	if (_dossierPrevSuspectMask.surf)
-		_dossierPrevSuspectMask.surf->free();
-	delete _dossierPrevSuspectMask.surf;
 	_dossierPrevSuspectMask.clear();
-
-	if (_dossierNextSheetMask.surf)
-		_dossierNextSheetMask.surf->free();
-	delete _dossierNextSheetMask.surf;
 	_dossierNextSheetMask.clear();
-
-	if (_dossierPrevSheetMask.surf)
-		_dossierPrevSheetMask.surf->free();
-	delete _dossierPrevSheetMask.surf;
 	_dossierPrevSheetMask.clear();
 
 	for (uint d = 0 ; d < 3; d++) {
-		if (_safeDigitArea[d].surf)
+		if (_safeDigitArea[d].surf) {
 			_safeDigitArea[d].surf->free();
-		delete _safeDigitArea[d].surf;
+			delete _safeDigitArea[d].surf;
+		}
 		_safeDigitArea[d].clear();
 		_safeDigit[d] = 0;
 		_safeDigitRect[d] = Common::Rect(0, 0);
@@ -905,9 +887,7 @@ bool PrivateEngine::selectDiaryPrevPage(Common::Point mousePos) {
 bool PrivateEngine::selectMemory(const Common::Point &mousePos) {
 	for (uint i = 0; i < _memoryMasks.size(); i++) {
 		if (inMask(_memoryMasks[i].surf, mousePos)) {
-			_masks.clear();
-			_memoryMasks.clear();
-			_exits.clear();
+			clearAreas();
 			_nextMovie = _diaryPages[_currentDiaryPage].memories[i].movie;
 			_nextSetting = "kDiaryMiddle";
 			return true;


Commit: 2268f80337f1273a2e1b146c82d007d207fea70d
    https://github.com/scummvm/scummvm/commit/2268f80337f1273a2e1b146c82d007d207fea70d
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-02T19:34:22+01:00

Commit Message:
PRIVATE: Fix memory leak when setting timer

Changed paths:
    engines/private/funcs.cpp
    engines/private/private.cpp


diff --git a/engines/private/funcs.cpp b/engines/private/funcs.cpp
index 96f2e19f6b2..77574b105d7 100644
--- a/engines/private/funcs.cpp
+++ b/engines/private/funcs.cpp
@@ -781,15 +781,11 @@ static void fTimer(ArgArray args) {
 		debugC(1, kPrivateDebugScript, "Timer(%d, %s)", args[0].u.val, args[1].u.str);
 
 	int32 delay = 1000000 * args[0].u.val;
-	// This pointer is necessary since installTimer needs one
-	Common::String *s = new Common::String(args[1].u.sym->name->c_str());
 	if (delay > 0) {
-		if (!g_private->installTimer(delay, s))
+		if (!g_private->installTimer(delay, args[1].u.sym->name))
 			error("Timer installation failed!");
 	} else if (delay == 0) {
-		g_private->_nextSetting = *s;
-		// No need to keep the pointer alive
-		delete s;
+		g_private->_nextSetting = *(args[1].u.sym->name);
 	} else {
 		assert(0);
 	}
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index 6d9dc8f019c..ef2e2903f10 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -468,6 +468,7 @@ Common::Error PrivateEngine::run() {
 			}
 		}
 	}
+	removeTimer();
 	return Common::kNoError;
 }
 
@@ -1824,7 +1825,7 @@ static void timerCallback(void *refCon) {
 }
 
 bool PrivateEngine::installTimer(uint32 delay, Common::String *ns) {
-	return g_system->getTimerManager()->installTimerProc(&timerCallback, delay, (void *)ns, "timerCallback");
+	return g_system->getTimerManager()->installTimerProc(&timerCallback, delay, ns, "timerCallback");
 }
 
 void PrivateEngine::removeTimer() {


Commit: e7ff9e9044077ccfb67ae1bdf6fb8f1a8cdcc002
    https://github.com/scummvm/scummvm/commit/e7ff9e9044077ccfb67ae1bdf6fb8f1a8cdcc002
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-02T19:34:22+01:00

Commit Message:
PRIVATE: Fixed memory leak in fCRect

Changed paths:
    engines/private/funcs.cpp
    engines/private/private.cpp
    engines/private/private.h


diff --git a/engines/private/funcs.cpp b/engines/private/funcs.cpp
index 77574b105d7..d5271c433ea 100644
--- a/engines/private/funcs.cpp
+++ b/engines/private/funcs.cpp
@@ -601,6 +601,7 @@ static void fCRect(ArgArray args) {
 	d.type = RECT;
 	d.u.rect = rect;
 	Gen::push(d);
+	g_private->_rects.push_back(rect);
 }
 
 static void fBitmap(ArgArray args) {
diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index ef2e2903f10..5ba621e4e2e 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -161,6 +161,11 @@ PrivateEngine::~PrivateEngine() {
 			delete m.surf;
 		}
 	}
+
+	for (RectList::iterator it = _rects.begin(); it != _rects.end(); ++it) {
+		Common::Rect *r = (*it);
+		delete r;
+	}
 }
 
 void PrivateEngine::initializePath(const Common::FSNode &gamePath) {
diff --git a/engines/private/private.h b/engines/private/private.h
index 84f7e01c992..7790651f128 100644
--- a/engines/private/private.h
+++ b/engines/private/private.h
@@ -144,6 +144,7 @@ typedef Common::List<MaskInfo> MaskList;
 typedef Common::List<Common::String> SoundList;
 typedef Common::List<PhoneInfo> PhoneList;
 typedef Common::List<Common::String> InvList;
+typedef Common::List<Common::Rect *> RectList;
 
 // arrays
 
@@ -382,6 +383,9 @@ public:
 	// Timers
 	bool installTimer(uint32, Common::String *);
 	void removeTimer();
+
+	// VM objects
+	RectList _rects; // created by fCRect
 };
 
 extern PrivateEngine *g_private;


Commit: 866d676616725ed6504c2ac1ade10f1ef071e15d
    https://github.com/scummvm/scummvm/commit/866d676616725ed6504c2ac1ade10f1ef071e15d
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-02T19:34:22+01:00

Commit Message:
PRIVATE: Fix memory leak in parser

Changed paths:
    engines/private/lexer.cpp
    engines/private/lexer.l


diff --git a/engines/private/lexer.cpp b/engines/private/lexer.cpp
index e0e7eb2df39..2012f4e19c1 100644
--- a/engines/private/lexer.cpp
+++ b/engines/private/lexer.cpp
@@ -2197,6 +2197,7 @@ int parse(const char *code) {
 	yy_switch_to_buffer(bp);
 	PRIVATE_parse();
 	yy_delete_buffer(bp);
+	yylex_destroy();
 	return 0;
 }
 
diff --git a/engines/private/lexer.l b/engines/private/lexer.l
index d56061f0344..c631a738469 100644
--- a/engines/private/lexer.l
+++ b/engines/private/lexer.l
@@ -87,6 +87,7 @@ int parse(const char *code) {
 	yy_switch_to_buffer(bp);
 	PRIVATE_parse();
 	yy_delete_buffer(bp);
+	yylex_destroy();
 	return 0;
 }
 


Commit: 28871bbd645941fb1f8a7590516ea716ac5693b0
    https://github.com/scummvm/scummvm/commit/28871bbd645941fb1f8a7590516ea716ac5693b0
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-02T19:34:22+01:00

Commit Message:
PRIVATE: Fix memory leaks in SymbolMaps and lexer

Changed paths:
    engines/private/lexer.cpp
    engines/private/lexer.l
    engines/private/symbol.cpp
    engines/private/symbol.h


diff --git a/engines/private/lexer.cpp b/engines/private/lexer.cpp
index 2012f4e19c1..279ca26a182 100644
--- a/engines/private/lexer.cpp
+++ b/engines/private/lexer.cpp
@@ -1182,7 +1182,7 @@ return RANDOMTOK;
 case 20:
 YY_RULE_SETUP
 #line 72 "engines/private/lexer.l"
-PRIVATE_lval.s = scumm_strdup(PRIVATE_text); return NAME;
+PRIVATE_lval.s = g_private->maps.string(PRIVATE_text); return NAME;
 	YY_BREAK
 case 21:
 YY_RULE_SETUP
@@ -1192,7 +1192,7 @@ PRIVATE_lval.sym = g_private->maps.constant(NUM, atoi(PRIVATE_text), NULL); retu
 case 22:
 YY_RULE_SETUP
 #line 74 "engines/private/lexer.l"
-PRIVATE_lval.sym = g_private->maps.constant(STRING, 0, scumm_strdup(PRIVATE_text)); return STRING;
+PRIVATE_lval.sym = g_private->maps.constant(STRING, 0, PRIVATE_text); return STRING;
 	YY_BREAK
 case 23:
 /* rule 23 can match eol */
diff --git a/engines/private/lexer.l b/engines/private/lexer.l
index c631a738469..67783b7cfae 100644
--- a/engines/private/lexer.l
+++ b/engines/private/lexer.l
@@ -69,9 +69,9 @@ FALSE			        return FALSETOK;
 TRUE					return TRUETOK;
 NULL					return NULLTOK;
 Random			        return RANDOMTOK;
-[A-Za-z_][A-Za-z_0-9]*  PRIVATE_lval.s = scumm_strdup(PRIVATE_text); return NAME;
+[A-Za-z_][A-Za-z_0-9]*  PRIVATE_lval.s = g_private->maps.string(PRIVATE_text); return NAME;
 [\-]?[0-9]+		        PRIVATE_lval.sym = g_private->maps.constant(NUM, atoi(PRIVATE_text), NULL); return NUM;
-\"[^\"\r\n]*\"	        PRIVATE_lval.sym = g_private->maps.constant(STRING, 0, scumm_strdup(PRIVATE_text)); return STRING;
+\"[^\"\r\n]*\"	        PRIVATE_lval.sym = g_private->maps.constant(STRING, 0, PRIVATE_text); return STRING;
 [\r|\n]+				/* ignore return */;
 [ \t]+		            /* ignore whitespace */;
 .				        return *yytext;
diff --git a/engines/private/symbol.cpp b/engines/private/symbol.cpp
index a296b4ac155..d7d8eddf1b9 100644
--- a/engines/private/symbol.cpp
+++ b/engines/private/symbol.cpp
@@ -49,6 +49,17 @@
 
 namespace Private {
 
+SymbolMaps::~SymbolMaps() {
+	freeSymbolMap(settings);
+	freeSymbolMap(variables);
+	freeSymbolMap(cursors);
+	freeSymbolMap(locations);
+	freeSymbolMap(rects);
+	freeSymbolList(constants);
+	freeSymbolList(names);
+	freeStringMap(strings);
+}
+
 void SymbolMaps::defineSymbol(const char *n, Common::Rect *r) {
 	Common::String s(n);
 	stringToDefine.push(s);
@@ -91,7 +102,7 @@ static Symbol *install(const Common::String &n, int t, int d, const char *s, Com
 		sp->u.val = d;
 		//debug("installing NAME: %s %d", name->c_str(), d);
 	} else if (t == STRING)
-		sp->u.str = scumm_strdup(s); // FIXME: leaks a string here.
+		sp->u.str = scumm_strdup(s);
 	else if (t == RECT)
 		sp->u.rect = r;
 	else
@@ -102,6 +113,19 @@ static Symbol *install(const Common::String &n, int t, int d, const char *s, Com
 	return sp;
 }
 
+void SymbolMaps::freeSymbolMap(SymbolMap &symbols) {
+	for (SymbolMap::iterator it = symbols.begin(); it != symbols.end(); ++it) {
+		Symbol *s = it->_value;
+		delete s->name;
+		if (s->type == STRING) {
+			free(s->u.str);
+		} else if (s->type == RECT) {
+			delete s->u.rect;
+		}
+		free(s);
+	}
+}
+
 /* lookup some name in some symbol table */
 Symbol *SymbolMaps::lookupRect(Common::String *n) {
 	assert(rects.contains(*n));
@@ -118,15 +142,14 @@ Symbol *SymbolMaps::lookupLocation(Common::String *n) {
 	return lookup(*n, locations);
 }
 
-/* lookup some name in some symbol table */
 Symbol *SymbolMaps::lookupName(const char *n) {
-
 	Symbol *s = (Symbol *)malloc(sizeof(Symbol));
 	Common::String *name = new Common::String(n);
 	s->name = name;
 	s->type = NAME;
 	s->u.val = 0;
 
+	names.push_back(s);
 	return s;
 }
 
@@ -171,7 +194,7 @@ Symbol *SymbolMaps::constant(int t, int d, const char *s) {
 	if (t == NUM || t == NAME)
 		sp->u.val = d;
 	else if (t == STRING)
-		sp->u.str = s;
+		sp->u.str = scumm_strdup(s);
 	else
 		assert(0);
 
@@ -179,4 +202,32 @@ Symbol *SymbolMaps::constant(int t, int d, const char *s) {
 	return sp;
 }
 
+void SymbolMaps::freeSymbolList(SymbolList &symbols) {
+	for (SymbolList::iterator it = symbols.begin(); it != symbols.end(); ++it) {
+		Symbol *s = (*it);
+		delete s->name;
+		if (s->type == STRING) {
+			free(s->u.str);
+		}
+		free(s);
+	}
+}
+
+char *SymbolMaps::string(const char *in) {
+	Common::String str(in);
+	char *out;
+	if (!strings.tryGetVal(in, out)) {
+		out = scumm_strdup(in);
+		strings[str] = out;
+	}
+	return out;
+}
+
+void SymbolMaps::freeStringMap(StringMap &strings) {
+	for (StringMap::iterator it = strings.begin(); it != strings.end(); ++it) {
+		char *s = it->_value;
+		free(s);
+	}
+}
+
 } // End of namespace Private
diff --git a/engines/private/symbol.h b/engines/private/symbol.h
index d9f4568a829..b57adc1e5d9 100644
--- a/engines/private/symbol.h
+++ b/engines/private/symbol.h
@@ -37,7 +37,7 @@ typedef struct Symbol {	 /* symbol table entry */
 	short  type;			/* NAME, NUM, STRING or RECT  */
 	union {
 		int val;			/* NAME or NUM */
-		const char *str;	/* STRING */
+		char *str;			/* STRING */
 		Common::Rect *rect; /* RECT */
 	} u;
 } Symbol;
@@ -48,7 +48,8 @@ void setSymbol(Symbol *, int);
 
 typedef Common::HashMap<Common::String, Symbol *> SymbolMap;
 typedef Common::List<Common::String> NameList;
-typedef Common::List<Symbol *> ConstantList;
+typedef Common::List<Symbol *> SymbolList;
+typedef Common::HashMap<Common::String, char *> StringMap;
 
 typedef Common::Queue<Common::String> StringQueue;
 typedef Common::Queue<Common::Rect *> RectQueue;
@@ -58,17 +59,26 @@ private:
 	StringQueue stringToDefine;
 	RectQueue rectToDefine;
 
+	static void freeSymbolMap(SymbolMap &symbols);
+	static void freeSymbolList(SymbolList &symbols);
+	static void freeStringMap(StringMap &strings);
 public:
 	SymbolMap settings;
 	SymbolMap variables;
 	SymbolMap cursors;
 	SymbolMap locations;
 	SymbolMap rects;
-	ConstantList constants;
+	SymbolList constants;
+	SymbolList names;
 
 	NameList variableList;
 	NameList locationList;
 
+	StringMap strings;
+
+	SymbolMaps() { }
+	~SymbolMaps();
+
 	Symbol *constant(int t, int d, const char *s);
 	Symbol *lookupVariable(Common::String *n);
 	Symbol *lookupLocation(Common::String *n);
@@ -76,6 +86,7 @@ public:
 	Symbol *lookupName(const char *n);
 	void installAll(const char *n);
 	void defineSymbol(const char *, Common::Rect *);
+	char *string(const char *in);
 };
 
 } // End of namespace Private


Commit: b3fd1bb2f3851b89b893d5f9e1dc09b5258394ed
    https://github.com/scummvm/scummvm/commit/b3fd1bb2f3851b89b893d5f9e1dc09b5258394ed
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-02T19:34:22+01:00

Commit Message:
PRIVATE: Fix memory leak when restarting game

Pausing a video and then starting a new game leaked the video decoder

Changed paths:
    engines/private/private.cpp


diff --git a/engines/private/private.cpp b/engines/private/private.cpp
index 5ba621e4e2e..b4dc6dcc234 100644
--- a/engines/private/private.cpp
+++ b/engines/private/private.cpp
@@ -1216,6 +1216,11 @@ void PrivateEngine::restartGame() {
 	// Movies
 	_repeatedMovieExit = "";
 	_playedMovies.clear();
+	if (_videoDecoder != _pausedVideo) {
+		delete _pausedVideo;
+	}
+	delete _videoDecoder;
+	_videoDecoder = nullptr;
 	_pausedVideo = nullptr;
 
 	// Pause


Commit: 4b556154520bfc318b23619bb5f6a7b468270a73
    https://github.com/scummvm/scummvm/commit/4b556154520bfc318b23619bb5f6a7b468270a73
Author: sluicebox (22204938+sluicebox at users.noreply.github.com)
Date: 2025-11-02T19:34:22+01:00

Commit Message:
PRIVATE: Fix loading cursors in Windows demos

Changed paths:
    engines/private/cursors.cpp


diff --git a/engines/private/cursors.cpp b/engines/private/cursors.cpp
index 9e0adfbc89c..c2b3d18828f 100644
--- a/engines/private/cursors.cpp
+++ b/engines/private/cursors.cpp
@@ -64,10 +64,16 @@ void PrivateEngine::loadCursors() {
 		Common::ArchiveMemberList members;
 		Common::InstallShieldV3 installerArchive;
 		if (installerArchive.open("SUPPORT/PVTEYE.Z")) {
-			const char *exeName = (_language == Common::JA_JPN) ? "PvteyeJ.EXE" : "PVTEYE.EXE";
-			exeStream = installerArchive.createReadStreamForMember(exeName);
+			const char *exeNames[] = {
+				"PVTEYE.EXE",
+				"PvteyeJ.EXE", // Japan
+				"PVTDEMO.EXE"
+			};
+			for (uint i = 0; i < ARRAYSIZE(exeNames) && exeStream == nullptr; i++) {
+				exeStream = installerArchive.createReadStreamForMember(exeNames[i]);
+			}
 			if (exeStream == nullptr) {
-				error("%s not found", exeName);
+				error("Executable not found in PVTEYE.Z");
 			}
 		} else {
 			Common::File *file = new Common::File();




More information about the Scummvm-git-logs mailing list