diff --git a/source/main.cpp b/source/main.cpp index 5b66ec06ea..96c599e700 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -372,6 +372,7 @@ static void RunGameOrAtlas(int argc, char* argv[]) while(!quit) Frame(); Shutdown(0); + ScriptingHost::FinalShutdown(); // this can't go in Shutdown() because that could be called multiple times per process, so stick it here instead MainControllerShutdown(); } diff --git a/source/ps/DllLoader.cpp b/source/ps/DllLoader.cpp index 2d3b711eca..49a5e31d95 100644 --- a/source/ps/DllLoader.cpp +++ b/source/ps/DllLoader.cpp @@ -4,6 +4,7 @@ #include "lib/posix/posix_dlfcn.h" #include "ps/CStr.h" +#include "ps/CLogger.h" void* const HANDLE_UNAVAILABLE = (void*)-1; @@ -65,7 +66,12 @@ bool DllLoader::LoadDLL() // open failed (mostly likely SO not found) if (! m_Handle) + { + char* error = dlerror(); + if (error) + LOG(ERROR, "", "dlopen error: %s", error); m_Handle = HANDLE_UNAVAILABLE; + } } return (m_Handle != HANDLE_UNAVAILABLE); diff --git a/source/ps/GameSetup/GameSetup.cpp b/source/ps/GameSetup/GameSetup.cpp index c8b109364c..5e60cfcce2 100644 --- a/source/ps/GameSetup/GameSetup.cpp +++ b/source/ps/GameSetup/GameSetup.cpp @@ -112,7 +112,7 @@ static int SetVideoMode(int w, int h, int bpp, bool fullscreen) // some kind of double-free problem causes a crash and lockup in the driver. // Calling SDL_Quit twice appears to be harmless, though, and avoids the problem // by destroying the context *before* the driver's atexit hook is called. - // (Note that atexit hooks are guarantueed to be called in reverse order of their registration.) + // (Note that atexit hooks are guaranteed to be called in reverse order of their registration.) atexit(SDL_Quit); // End work around. diff --git a/source/scripting/ScriptingHost.cpp b/source/scripting/ScriptingHost.cpp index 434d55ff15..6cfb0be2c4 100644 --- a/source/scripting/ScriptingHost.cpp +++ b/source/scripting/ScriptingHost.cpp @@ -82,7 +82,13 @@ ScriptingHost::~ScriptingHost() JS_DestroyRuntime(m_RunTime); m_RunTime = NULL; } +} +void ScriptingHost::FinalShutdown() +{ + // This should only be called once per process, just to clean up before + // we report memory leaks. (Otherwise, if it's called while there are + // other contexts active in other threads, things will break.) JS_ShutDown(); } diff --git a/source/scripting/ScriptingHost.h b/source/scripting/ScriptingHost.h index 27c647ba00..9bd5c87722 100644 --- a/source/scripting/ScriptingHost.h +++ b/source/scripting/ScriptingHost.h @@ -77,6 +77,8 @@ public: ScriptingHost(); ~ScriptingHost(); + + static void FinalShutdown(); // Helpers: diff --git a/source/tools/atlas/AtlasObject/AtlasObject.h b/source/tools/atlas/AtlasObject/AtlasObject.h index 68d9a20858..755ad14df2 100644 --- a/source/tools/atlas/AtlasObject/AtlasObject.h +++ b/source/tools/atlas/AtlasObject/AtlasObject.h @@ -12,12 +12,17 @@ ////////////////////////////////////////////////////////////////////////// // Mostly-private bits: +// Helper class to let us define a conversion operator only for AtSmartPtr +template struct ConstCastHelper { operator ConstSmPtr (); }; +template struct ConstCastHelper { }; + // Simple reference-counted pointer. class T must contain a reference count, // initialised to 0. An external implementation (in AtlasObjectImpl.cpp) // provides the inc_ref and dec_ref methods, so that this header file doesn't // need to know their implementations. -template class AtSmartPtr +template class AtSmartPtr : public ConstCastHelper, T> { + friend struct ConstCastHelper, T>; public: // Constructors AtSmartPtr() : ptr(NULL) {} @@ -30,7 +35,7 @@ public: // Destructor ~AtSmartPtr() { dec_ref(); } // Allow conversion from non-const T* to const T* - operator AtSmartPtr () { return AtSmartPtr(ptr); } + //operator AtSmartPtr () { return AtSmartPtr(ptr); } // (actually provided by ConstCastHelper) // Override -> T* operator->() const { return ptr; } // Test whether the pointer is pointing to anything @@ -42,6 +47,12 @@ private: T* ptr; }; +template +ConstCastHelper::operator ConstSmPtr () +{ + return ConstSmPtr(static_cast*>(this)->ptr); +} + // A few required declarations class AtObj; class AtNode; diff --git a/source/tools/atlas/GameInterface/GameLoop.cpp b/source/tools/atlas/GameInterface/GameLoop.cpp index f52f558df5..c01af15dee 100644 --- a/source/tools/atlas/GameInterface/GameLoop.cpp +++ b/source/tools/atlas/GameInterface/GameLoop.cpp @@ -253,6 +253,7 @@ bool BeginAtlas(const CmdLineArgs& args, const DllLoader& dll) // Clean up View::DestroyViews(); + ScriptingHost::FinalShutdown(); return true; } diff --git a/source/tools/atlas/GameInterface/Shareable.h b/source/tools/atlas/GameInterface/Shareable.h index cf635049ca..507c1b4c8d 100644 --- a/source/tools/atlas/GameInterface/Shareable.h +++ b/source/tools/atlas/GameInterface/Shareable.h @@ -11,7 +11,7 @@ the same way. So, the Shareable class is used to make things a bit safer: Simple types (primitives, basic structs, etc) are passed as normal. std::string is converted to an array, using a shared (and thread-safe) memory -allocation function so that it works when the DLL and EXE use different heaps. +allocation function so that it works when the DLL and EXE use different heaps. std::vector is done the same, though its element type must be Shareable too. This ought to protect against: