diff --git a/amxmodx/CPlugin.cpp b/amxmodx/CPlugin.cpp index b3b13637..9ee09260 100755 --- a/amxmodx/CPlugin.cpp +++ b/amxmodx/CPlugin.cpp @@ -130,6 +130,8 @@ int CPluginMngr::loadPluginsFromFile(const char* filename) fclose(fp); + InvalidateCache(); + return pCounter; } @@ -383,3 +385,88 @@ void CPluginMngr::CPlugin::unpausePlugin() executeForwards(m_UnpauseFwd); } } + +char *CPluginMngr::ReadIntoOrFromCache(const char *file, size_t &bufsize) +{ + List::iterator iter; + plcache_entry *pl; + + for (iter=m_plcache.begin(); iter!=m_plcache.end(); iter++) + { + pl = (*iter); + if (pl->path.compare(file) == 0) + { + bufsize = pl->bufsize; + return pl->buffer; + } + } + + pl = new plcache_entry; + + pl->file = new CAmxxReader(file, sizeof(cell)); + if (pl->file->GetStatus() != CAmxxReader::Err_None) + { + delete pl->file; + delete pl; + return NULL; + } + + pl->bufsize =pl->file->GetBufferSize(); + pl->buffer = NULL; + if (pl->bufsize) + { + pl->buffer = new char[pl->bufsize]; + pl->file->GetSection(pl->buffer); + } + + if (!pl->bufsize || pl->file->GetStatus() != CAmxxReader::Err_None) + { + delete [] pl->buffer; + delete pl->file; + delete pl; + return NULL; + } + + pl->path.assign(file); + + bufsize = pl->bufsize; + + return pl->buffer; +} + +void CPluginMngr::InvalidateCache() +{ + List::iterator iter; + plcache_entry *pl; + + for (iter=m_plcache.begin(); iter!=m_plcache.end(); iter++) + { + pl = (*iter); + delete [] pl->buffer; + delete pl->file; + delete pl; + } + + m_plcache.clear(); +} + +void CPluginMngr::InvalidateFileInCache(const char *file, bool freebuf) +{ + List::iterator iter; + plcache_entry *pl; + + for (iter=m_plcache.begin(); iter!=m_plcache.end(); iter++) + { + pl = (*iter); + if (pl->path.compare(file) == 0) + { + if (freebuf) + delete [] pl->buffer; + delete pl->file; + delete pl; + m_plcache.erase(iter); + return; + } + } +} + diff --git a/amxmodx/CPlugin.h b/amxmodx/CPlugin.h index 7b70e2ea..ad67b50c 100755 --- a/amxmodx/CPlugin.h +++ b/amxmodx/CPlugin.h @@ -32,6 +32,11 @@ #ifndef PLUGIN_H #define PLUGIN_H +#include "CString.h" +#include "sh_list.h" +#include "amx.h" +#include "amxxfile.h" + // ***************************************************** // class CPluginMngr // ***************************************************** @@ -111,7 +116,7 @@ private: int pCounter; public: CPluginMngr() { head = 0; pCounter = 0; pNatives = NULL; m_Finalized=false;} - ~CPluginMngr() { clear(); } + ~CPluginMngr() { clear(); InvalidateCache(); } bool m_Finalized; AMX_NATIVE_INFO *pNatives; @@ -145,6 +150,19 @@ public: inline iterator begin() const { return iterator(head); } inline iterator end() const { return iterator(0); } +public: + struct plcache_entry + { + CAmxxReader *file; + size_t bufsize; + char *buffer; + String path; + }; + char *ReadIntoOrFromCache(const char *file, size_t &bufsize); + void InvalidateCache(); + void InvalidateFileInCache(const char *file, bool freebuf); +private: + List m_plcache; }; #endif //PLUGIN_H diff --git a/amxmodx/modules.cpp b/amxmodx/modules.cpp index 582aeed8..e1a90f87 100755 --- a/amxmodx/modules.cpp +++ b/amxmodx/modules.cpp @@ -162,56 +162,63 @@ static binlogfuncs_t logfuncs = int load_amxscript(AMX *amx, void **program, const char *filename, char error[64], int debug) { *error = 0; - CAmxxReader reader(filename, PAWN_CELL_SIZE / 8); - - if (reader.GetStatus() == CAmxxReader::Err_None) + size_t bufSize; + *program = (void *)g_plugins.ReadIntoOrFromCache(filename, bufSize); + if (!*program) { - size_t bufSize = reader.GetBufferSize(); + CAmxxReader reader(filename, PAWN_CELL_SIZE / 8); - if (bufSize != 0) + if (reader.GetStatus() == CAmxxReader::Err_None) { - *program = (void*) (new char[bufSize]); + bufSize = reader.GetBufferSize(); - if (!*program) + if (bufSize != 0) { - strcpy(error, "Failed to allocate memory"); - return (amx->error = AMX_ERR_MEMORY); + *program = (void*) (new char[bufSize]); + + if (!*program) + { + strcpy(error, "Failed to allocate memory"); + return (amx->error = AMX_ERR_MEMORY); + } + + reader.GetSection(*program); } - - reader.GetSection(*program); } - } - - switch (reader.GetStatus()) - { - case CAmxxReader::Err_None: - break; - case CAmxxReader::Err_FileOpen: - strcpy(error, "Plugin file open error"); - return (amx->error = AMX_ERR_NOTFOUND); - case CAmxxReader::Err_FileRead: - strcpy(error, "Plugin file read error"); - return (amx->error = AMX_ERR_NOTFOUND); - case CAmxxReader::Err_InvalidParam: - strcpy(error, "Internal error: Invalid parameter"); - return (amx->error = AMX_ERR_NOTFOUND); - case CAmxxReader::Err_FileInvalid: - strcpy(error, "Invalid Plugin"); - return (amx->error = AMX_ERR_FORMAT); - case CAmxxReader::Err_SectionNotFound: - strcpy(error, "Searched section not found (.amxx)"); - return (amx->error = AMX_ERR_NOTFOUND); - case CAmxxReader::Err_DecompressorInit: - strcpy(error, "Decompressor initialization failed"); - return (amx->error = AMX_ERR_INIT); - case CAmxxReader::Err_Decompress: - strcpy(error, "Internal error: Decompress"); - return (amx->error = AMX_ERR_NOTFOUND); - case CAmxxReader::Err_OldFile: - strcpy(error, "Plugin uses deprecated format. Update compiler"); - default: - strcpy(error, "Unknown error"); - return (amx->error = AMX_ERR_NOTFOUND); + + switch (reader.GetStatus()) + { + case CAmxxReader::Err_None: + break; + case CAmxxReader::Err_FileOpen: + strcpy(error, "Plugin file open error"); + return (amx->error = AMX_ERR_NOTFOUND); + case CAmxxReader::Err_FileRead: + strcpy(error, "Plugin file read error"); + return (amx->error = AMX_ERR_NOTFOUND); + case CAmxxReader::Err_InvalidParam: + strcpy(error, "Internal error: Invalid parameter"); + return (amx->error = AMX_ERR_NOTFOUND); + case CAmxxReader::Err_FileInvalid: + strcpy(error, "Invalid Plugin"); + return (amx->error = AMX_ERR_FORMAT); + case CAmxxReader::Err_SectionNotFound: + strcpy(error, "Searched section not found (.amxx)"); + return (amx->error = AMX_ERR_NOTFOUND); + case CAmxxReader::Err_DecompressorInit: + strcpy(error, "Decompressor initialization failed"); + return (amx->error = AMX_ERR_INIT); + case CAmxxReader::Err_Decompress: + strcpy(error, "Internal error: Decompress"); + return (amx->error = AMX_ERR_NOTFOUND); + case CAmxxReader::Err_OldFile: + strcpy(error, "Plugin uses deprecated format. Update compiler"); + default: + strcpy(error, "Unknown error"); + return (amx->error = AMX_ERR_NOTFOUND); + } + } else { + g_plugins.InvalidateFileInCache(filename, false); } // check for magic @@ -337,12 +344,12 @@ int load_amxscript(AMX *amx, void **program, const char *filename, char error[64 if (amx->base) memcpy(amx->base, np, amx->code_size); - delete[] np; - delete[] rt; + delete [] np; + delete [] rt; char *prg = (char *)(*program); - delete[] prg; + delete [] prg; (*program) = amx->base; if (*program == 0) @@ -363,12 +370,6 @@ int load_amxscript(AMX *amx, void **program, const char *filename, char error[64 CScript* aa = new CScript(amx, *program, filename); - if (aa == 0) - { - strcpy(error, "Failed to allocate memory"); - return (amx->error = AMX_ERR_MEMORY); - } - g_loadedscripts.put(aa); set_amxnatives(amx, error); diff --git a/amxmodx/natives.cpp b/amxmodx/natives.cpp index dfd16b7f..bf165335 100755 --- a/amxmodx/natives.cpp +++ b/amxmodx/natives.cpp @@ -68,10 +68,27 @@ int amxx_DynaCallback(int idx, AMX *amx, cell *params) return 0; } - //parameter stack - pNative->caller = amx; - CPluginMngr::CPlugin *pPlugin = g_plugins.findPluginFast(amx); + CPluginMngr::CPlugin *pNativePlugin = g_plugins.findPluginFast(pNative->amx); + + if (!pNativePlugin->isExecutable(pNative->func)) + { + LogError(amx, AMX_ERR_NATIVE, "Called dynanative into a paused plugin."); + pPlugin->setStatus(ps_paused); + return 0; + } + + if (pNative->caller) + { + LogError(amx, AMX_ERR_NATIVE, "Bug caught! Please contact the AMX Mod X Dev Team."); + return 0; + } + + //parameter stack + //NOTE: it is possible that recursive register native calling + // could potentially be somehow damaged here. + //so, a :TODO: - make the stack unique, rather than a known ptr + pNative->caller = amx; int err = 0; cell ret = 0; @@ -112,6 +129,8 @@ int amxx_DynaCallback(int idx, AMX *amx, cell *params) g_NativeStack.pop(); g_ErrorStk.pop(); + pNative->caller = NULL; + return ret; } @@ -370,6 +389,7 @@ static cell AMX_NATIVE_CALL register_native(AMX *amx, cell *params) regnative *pNative = new regnative; pNative->amx = amx; pNative->func = idx; + pNative->caller = NULL; //we'll apply a safety buffer too //make our function