mirror of
https://github.com/isledecomp/isle-portable.git
synced 2026-05-25 12:46:34 +00:00
Fix ROI UAF cluster and bump Emscripten INITIAL_MEMORY to 128 MB (#807)
ROI UAF fixes: - LegoAnimActorStruct deep-copies m_roiMap and deletes copy-assignment, so LegoExtraActor's copy-construction at legoextraactor.cpp no longer shares ownership with the source presenter. - LegoROI tracks slot back-references; its destructor nulls every registered LegoROI** so per-element UAF in arrays like LegoAnimPresenter::m_roiMap is impossible. LegoAnimActorStruct / LegoAnimPresenter / LegoLocomotionAnimPresenter register and unregister around their array lifetimes. - LegoAnimationManager::Suspend now invokes ClearMaps on every persistent LegoExtraActor (not just those currently in m_extras) so dormant actors cannot retain stale m_AnimTreePtr after world teardown. Adds ClearMaps overrides on Act2Actor, Act3Cop, Act3Brickster, Act3Shark, LegoRaceCar, LegoExtraActor. INITIAL_MEMORY=128mb is re-added to the Emscripten link options.
This commit is contained in:
parent
298e02b858
commit
9e82c461dd
@ -14,7 +14,7 @@ endif()
|
||||
|
||||
if (EMSCRIPTEN)
|
||||
add_compile_options(-pthread -gsource-map)
|
||||
add_link_options(-sUSE_WEBGL2=1 -sMIN_WEBGL_VERSION=2 -sALLOW_MEMORY_GROWTH=1 -sMAXIMUM_MEMORY=2gb -sUSE_PTHREADS=1 -sPROXY_TO_PTHREAD=1 -sOFFSCREENCANVAS_SUPPORT=1 -sPTHREAD_POOL_SIZE_STRICT=0 -sFORCE_FILESYSTEM=1 -sWASMFS=1 -sEXIT_RUNTIME=1 -sABORT_ON_WASM_EXCEPTIONS=1 -gsource-map)
|
||||
add_link_options(-sUSE_WEBGL2=1 -sMIN_WEBGL_VERSION=2 -sALLOW_MEMORY_GROWTH=1 -sINITIAL_MEMORY=128mb -sMAXIMUM_MEMORY=2gb -sUSE_PTHREADS=1 -sPROXY_TO_PTHREAD=1 -sOFFSCREENCANVAS_SUPPORT=1 -sPTHREAD_POOL_SIZE_STRICT=0 -sFORCE_FILESYSTEM=1 -sWASMFS=1 -sEXIT_RUNTIME=1 -sABORT_ON_WASM_EXCEPTIONS=1 -gsource-map)
|
||||
set(SDL_PTHREADS ON CACHE BOOL "Enable SDL pthreads" FORCE)
|
||||
find_program(LLVM_OBJCOPY_BIN NAMES llvm-objcopy HINTS "${EMSCRIPTEN_ROOT_PATH}/../bin" REQUIRED)
|
||||
set(ISLE_EMSCRIPTEN_VERSION_DIR "${CMAKE_BINARY_DIR}/generated")
|
||||
|
||||
@ -39,6 +39,7 @@ class Act2Actor : public LegoAnimActor {
|
||||
} // vtable+0x68
|
||||
|
||||
void Animate(float p_time) override; // vtable+0x70
|
||||
void ClearMaps() override; // vtable+0x84
|
||||
MxResult HitActor(LegoPathActor*, MxBool) override; // vtable+0x94
|
||||
MxResult CalculateSpline() override; // vtable+0x9c
|
||||
MxS32 NextTargetLocation() override; // vtable+0xa0
|
||||
|
||||
@ -19,6 +19,7 @@ class Act3Shark : public LegoAnimActor {
|
||||
|
||||
void ParseAction(char*) override; // vtable+0x20
|
||||
void Animate(float p_time) override; // vtable+0x70
|
||||
void ClearMaps() override; // vtable+0x84
|
||||
|
||||
// LegoAnimActor vtable
|
||||
virtual MxResult EatPizza(Act3Ammo* p_ammo); // vtable+0x10
|
||||
@ -104,6 +105,7 @@ class Act3Cop : public Act3Actor {
|
||||
|
||||
void ParseAction(char* p_extra) override; // vtable+0x20
|
||||
void Animate(float p_time) override; // vtable+0x70
|
||||
void ClearMaps() override; // vtable+0x84
|
||||
MxResult HitActor(LegoPathActor*, MxBool) override; // vtable+0x94
|
||||
MxResult CalculateSpline() override; // vtable+0x9c
|
||||
|
||||
@ -137,6 +139,7 @@ class Act3Brickster : public Act3Actor {
|
||||
|
||||
void ParseAction(char* p_extra) override; // vtable+0x20
|
||||
void Animate(float p_time) override; // vtable+0x70
|
||||
void ClearMaps() override; // vtable+0x84
|
||||
MxResult HitActor(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94
|
||||
void SwitchBoundary(
|
||||
LegoPathBoundary*& p_boundary,
|
||||
|
||||
@ -9,6 +9,8 @@ class LegoAnim;
|
||||
// SIZE 0x20
|
||||
struct LegoAnimActorStruct {
|
||||
LegoAnimActorStruct(float p_worldSpeed, LegoAnim* p_AnimTreePtr, LegoROI** p_roiMap, MxU32 p_numROIs);
|
||||
LegoAnimActorStruct(const LegoAnimActorStruct& p_other);
|
||||
LegoAnimActorStruct& operator=(const LegoAnimActorStruct&) = delete;
|
||||
~LegoAnimActorStruct();
|
||||
|
||||
float GetDuration();
|
||||
|
||||
@ -49,6 +49,7 @@ class LegoExtraActor : public virtual LegoAnimActor {
|
||||
) override; // vtable+0x6c
|
||||
void Animate(float p_time) override; // vtable+0x70
|
||||
void ApplyTransform(Matrix4& p_transform) override; // vtable+0x74
|
||||
void ClearMaps() override; // vtable+0x84
|
||||
MxU32 StepState(float p_time, Matrix4& p_matrix) override; // vtable+0x90
|
||||
MxResult HitActor(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94
|
||||
MxResult CalculateSpline() override; // vtable+0x9c
|
||||
|
||||
@ -160,6 +160,7 @@ class LegoRaceCar : public LegoCarRaceActor, public LegoRaceMap {
|
||||
} // vtable+0x6c
|
||||
|
||||
void Animate(float p_time) override; // vtable+0x70
|
||||
void ClearMaps() override; // vtable+0x84
|
||||
MxResult HitActor(LegoPathActor* p_actor, MxBool p_bool) override; // vtable+0x94
|
||||
|
||||
// FUNCTION: LEGO1 0x10014560
|
||||
|
||||
@ -877,3 +877,9 @@ LegoEntity* Act2Actor::GetNextEntity(MxBool* p_isBuilding)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void Act2Actor::ClearMaps()
|
||||
{
|
||||
m_shootAnim = NULL;
|
||||
LegoAnimActor::ClearMaps();
|
||||
}
|
||||
|
||||
@ -1231,3 +1231,22 @@ void Act3Shark::ParseAction(char* p_extra)
|
||||
m_unk0x38->SetVisibility(FALSE);
|
||||
m_world->PlaceActor(this);
|
||||
}
|
||||
|
||||
void Act3Cop::ClearMaps()
|
||||
{
|
||||
m_eatAnim = NULL;
|
||||
Act3Actor::ClearMaps();
|
||||
}
|
||||
|
||||
void Act3Brickster::ClearMaps()
|
||||
{
|
||||
m_shootAnim = NULL;
|
||||
Act3Actor::ClearMaps();
|
||||
}
|
||||
|
||||
void Act3Shark::ClearMaps()
|
||||
{
|
||||
m_unk0x34 = NULL;
|
||||
m_unk0x38 = NULL;
|
||||
LegoAnimActor::ClearMaps();
|
||||
}
|
||||
|
||||
@ -437,11 +437,14 @@ void LegoAnimationManager::Suspend()
|
||||
LegoROI* roi = m_extras[i].m_roi;
|
||||
|
||||
if (roi != NULL) {
|
||||
LegoPathActor* actor = CharacterManager()->GetExtraActor(roi->GetName());
|
||||
LegoExtraActor* actor = CharacterManager()->GetExtraActor(roi->GetName());
|
||||
|
||||
if (actor != NULL && actor->GetController() != NULL) {
|
||||
actor->GetController()->RemoveActor(actor);
|
||||
actor->SetController(NULL);
|
||||
if (actor != NULL) {
|
||||
if (actor->GetController() != NULL) {
|
||||
actor->GetController()->RemoveActor(actor);
|
||||
actor->SetController(NULL);
|
||||
}
|
||||
actor->ClearMaps();
|
||||
}
|
||||
|
||||
CharacterManager()->ReleaseActor(roi);
|
||||
@ -466,6 +469,18 @@ void LegoAnimationManager::Suspend()
|
||||
m_extras[i].m_speed = -1.0f;
|
||||
}
|
||||
|
||||
// Catch dormant actors too: despawn paths null m_extras[i].m_roi
|
||||
// without ClearMaps, leaving stale m_AnimTreePtr behind.
|
||||
for (i = 0; i < (MxS32) CharacterManager()->GetNumActors(); i++) {
|
||||
const char* name = CharacterManager()->GetActorName(i);
|
||||
if (name != NULL) {
|
||||
LegoExtraActor* extraActor = CharacterManager()->GetExtraActor(name);
|
||||
if (extraActor != NULL) {
|
||||
extraActor->ClearMaps();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_unk0x18 = 0;
|
||||
m_unk0x1a = FALSE;
|
||||
m_enableCamAnims = FALSE;
|
||||
|
||||
@ -22,13 +22,39 @@ LegoAnimActorStruct::LegoAnimActorStruct(
|
||||
{
|
||||
m_worldSpeed = p_worldSpeed;
|
||||
m_AnimTreePtr = p_AnimTreePtr;
|
||||
m_roiMap = p_roiMap;
|
||||
m_numROIs = p_numROIs;
|
||||
// Deep copy: source array's owner may outlive or rebuild it independently.
|
||||
m_roiMap = new LegoROI*[p_numROIs + 1];
|
||||
memcpy(m_roiMap, p_roiMap, (p_numROIs + 1) * sizeof(LegoROI*));
|
||||
for (MxU32 i = 0; i <= p_numROIs; i++) {
|
||||
if (m_roiMap[i]) {
|
||||
m_roiMap[i]->RegisterSlotRef(&m_roiMap[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LegoAnimActorStruct::LegoAnimActorStruct(const LegoAnimActorStruct& p_other)
|
||||
: m_worldSpeed(p_other.m_worldSpeed), m_AnimTreePtr(p_other.m_AnimTreePtr), m_numROIs(p_other.m_numROIs),
|
||||
m_unk0x10(p_other.m_unk0x10)
|
||||
{
|
||||
m_roiMap = new LegoROI*[m_numROIs + 1];
|
||||
memcpy(m_roiMap, p_other.m_roiMap, (m_numROIs + 1) * sizeof(LegoROI*));
|
||||
for (MxU32 i = 0; i <= m_numROIs; i++) {
|
||||
if (m_roiMap[i]) {
|
||||
m_roiMap[i]->RegisterSlotRef(&m_roiMap[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FUNCTION: LEGO1 0x1001c0a0
|
||||
LegoAnimActorStruct::~LegoAnimActorStruct()
|
||||
{
|
||||
for (MxU32 i = 0; i <= m_numROIs; i++) {
|
||||
if (m_roiMap[i]) {
|
||||
m_roiMap[i]->UnregisterSlotRef(&m_roiMap[i]);
|
||||
}
|
||||
}
|
||||
delete[] m_roiMap;
|
||||
for (MxU16 i = 0; i < m_unk0x10.size(); i++) {
|
||||
delete m_unk0x10[i];
|
||||
}
|
||||
|
||||
@ -536,3 +536,12 @@ inline MxU32 LegoExtraActor::CheckPresenterAndActorIntersections(
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void LegoExtraActor::ClearMaps()
|
||||
{
|
||||
delete m_assAnim;
|
||||
m_assAnim = NULL;
|
||||
delete m_disAnim;
|
||||
m_disAnim = NULL;
|
||||
LegoAnimActor::ClearMaps();
|
||||
}
|
||||
|
||||
@ -736,3 +736,10 @@ MxResult LegoJetski::HitActor(LegoPathActor* p_actor, MxBool p_bool)
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
void LegoRaceCar::ClearMaps()
|
||||
{
|
||||
m_skelKick1Anim = NULL;
|
||||
m_skelKick2Anim = NULL;
|
||||
LegoAnimActor::ClearMaps();
|
||||
}
|
||||
|
||||
@ -86,6 +86,11 @@ void LegoAnimPresenter::Destroy(MxBool p_fromDestructor)
|
||||
}
|
||||
|
||||
if (m_roiMap != NULL) {
|
||||
for (MxU32 i = 0; i <= m_roiMapSize; i++) {
|
||||
if (m_roiMap[i]) {
|
||||
m_roiMap[i]->UnregisterSlotRef(&m_roiMap[i]);
|
||||
}
|
||||
}
|
||||
delete[] m_roiMap;
|
||||
}
|
||||
|
||||
@ -126,6 +131,11 @@ void LegoAnimPresenter::Destroy(MxBool p_fromDestructor)
|
||||
}
|
||||
|
||||
if (m_ptAtCamROI != NULL) {
|
||||
for (MxS32 i = 0; i < m_ptAtCamCount; i++) {
|
||||
if (m_ptAtCamROI[i]) {
|
||||
m_ptAtCamROI[i]->UnregisterSlotRef(&m_ptAtCamROI[i]);
|
||||
}
|
||||
}
|
||||
delete[] m_ptAtCamROI;
|
||||
}
|
||||
|
||||
@ -415,12 +425,22 @@ void LegoAnimPresenter::BuildROIMap()
|
||||
LegoAnimStructMap anims;
|
||||
|
||||
if (m_ptAtCamROI != NULL) {
|
||||
for (MxS32 i = 0; i < m_ptAtCamCount; i++) {
|
||||
if (m_ptAtCamROI[i]) {
|
||||
m_ptAtCamROI[i]->UnregisterSlotRef(&m_ptAtCamROI[i]);
|
||||
}
|
||||
}
|
||||
memset(m_ptAtCamROI, 0, m_ptAtCamCount * sizeof(*m_ptAtCamROI));
|
||||
}
|
||||
|
||||
UpdateStructMapAndROIIndex(anims, m_anim->GetRoot(), NULL);
|
||||
|
||||
if (m_roiMap != NULL) {
|
||||
for (MxU32 i = 0; i <= m_roiMapSize; i++) {
|
||||
if (m_roiMap[i]) {
|
||||
m_roiMap[i]->UnregisterSlotRef(&m_roiMap[i]);
|
||||
}
|
||||
}
|
||||
delete[] m_roiMap;
|
||||
m_roiMapSize = 0;
|
||||
}
|
||||
@ -432,12 +452,14 @@ void LegoAnimPresenter::BuildROIMap()
|
||||
for (LegoAnimStructMap::iterator it = anims.begin(); it != anims.end();) {
|
||||
MxU32 index = (*it).second.m_index;
|
||||
m_roiMap[index] = (*it).second.m_roi;
|
||||
m_roiMap[index]->RegisterSlotRef(&m_roiMap[index]);
|
||||
|
||||
if (m_roiMap[index]->GetName() != NULL) {
|
||||
for (MxS32 i = 0; i < m_ptAtCamCount; i++) {
|
||||
if (m_ptAtCamROI[i] == NULL && m_ptAtCamNames[i] != NULL) {
|
||||
if (!SDL_strcasecmp(m_ptAtCamNames[i], m_roiMap[index]->GetName())) {
|
||||
m_ptAtCamROI[i] = m_roiMap[index];
|
||||
m_ptAtCamROI[i]->RegisterSlotRef(&m_ptAtCamROI[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -1025,6 +1047,11 @@ void LegoAnimPresenter::ParseExtra()
|
||||
}
|
||||
|
||||
if (m_ptAtCamROI != NULL) {
|
||||
for (MxS32 i = 0; i < m_ptAtCamCount; i++) {
|
||||
if (m_ptAtCamROI[i]) {
|
||||
m_ptAtCamROI[i]->UnregisterSlotRef(&m_ptAtCamROI[i]);
|
||||
}
|
||||
}
|
||||
delete[] m_ptAtCamROI;
|
||||
m_ptAtCamROI = NULL;
|
||||
}
|
||||
@ -1447,6 +1474,13 @@ void LegoLocomotionAnimPresenter::CreateROIAndBuildMap(LegoAnimActor* p_actor, M
|
||||
if (m_roiMap != NULL) {
|
||||
m_roiMapList->Append(m_roiMap);
|
||||
p_actor->CreateAnimActorStruct(m_anim, p_worldSpeed, m_roiMap, m_roiMapSize);
|
||||
|
||||
for (MxU32 i = 0; i <= m_roiMapSize; i++) {
|
||||
if (m_roiMap[i]) {
|
||||
m_roiMap[i]->UnregisterSlotRef(&m_roiMap[i]);
|
||||
}
|
||||
}
|
||||
|
||||
m_roiMap = NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -96,6 +96,9 @@ LegoROI::LegoROI(Tgl::Renderer* p_renderer, ViewLODList* p_lodList) : ViewROI(p_
|
||||
// FUNCTION: BETA10 0x10189a42
|
||||
LegoROI::~LegoROI()
|
||||
{
|
||||
for (LegoROI** slot : m_slotRefs) {
|
||||
*slot = NULL;
|
||||
}
|
||||
if (comp) {
|
||||
CompoundObject::iterator iterator;
|
||||
|
||||
|
||||
@ -5,6 +5,9 @@
|
||||
#include "misc/legotypes.h"
|
||||
#include "viewmanager/viewroi.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
|
||||
typedef unsigned char (*ColorOverride)(const char*, char*, unsigned int);
|
||||
typedef unsigned char (*TextureHandler)(const char*, unsigned char*, unsigned int);
|
||||
|
||||
@ -99,6 +102,15 @@ class LegoROI : public ViewROI {
|
||||
void SetBoundingSphere(const BoundingSphere& p_sphere) { m_sphere = m_world_bounding_sphere = p_sphere; }
|
||||
void SetBoundingBox(const BoundingBox& p_box) { m_bounding_box = p_box; }
|
||||
|
||||
void RegisterSlotRef(LegoROI** p_slot) { m_slotRefs.push_back(p_slot); }
|
||||
void UnregisterSlotRef(LegoROI** p_slot)
|
||||
{
|
||||
std::vector<LegoROI**>::iterator it = std::find(m_slotRefs.begin(), m_slotRefs.end(), p_slot);
|
||||
if (it != m_slotRefs.end()) {
|
||||
m_slotRefs.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
// SYNTHETIC: LEGO1 0x100a82b0
|
||||
// SYNTHETIC: BETA10 0x1018c490
|
||||
// LegoROI::`scalar deleting destructor'
|
||||
@ -108,6 +120,7 @@ class LegoROI : public ViewROI {
|
||||
BoundingSphere m_sphere; // 0xe8
|
||||
LegoBool m_sharedLodList; // 0x100
|
||||
LegoEntity* m_entity; // 0x104
|
||||
std::vector<LegoROI**> m_slotRefs;
|
||||
};
|
||||
|
||||
// VTABLE: LEGO1 0x100dbea8
|
||||
|
||||
Loading…
Reference in New Issue
Block a user