diff --git a/core/msvc8/sourcemod_mm.vcproj b/core/msvc8/sourcemod_mm.vcproj index 43282eceb..a4b30dd06 100644 --- a/core/msvc8/sourcemod_mm.vcproj +++ b/core/msvc8/sourcemod_mm.vcproj @@ -1,7 +1,7 @@ + + + + + + + + + + + + + + + pContext->GetContext())->GetFilename()); + g_DbgReporter.GenerateError(pInfo->pContext, + pInfo->Hook->GetFunctionID(), + SP_ERROR_NATIVE, + "Invalid data handle %x (error %d) passed during timer end", + usrhndl, + herr); } } if ((herr=g_HandleSys.FreeHandle(pInfo->TimerHandle, &sec)) != HandleError_None) { - g_Logger.LogError("Invalid timer handle %x (error %d) on plugin %s during timer end", - pInfo->TimerHandle, - herr, - g_PluginSys.FindPluginByContext(pInfo->pContext->GetContext())->GetFilename()); + g_DbgReporter.GenerateError(pInfo->pContext, + pInfo->Hook->GetFunctionID(), + SP_ERROR_NATIVE, + "Invalid timer handle %x (error %d) during timer end, displayed function is timer callback, not the stack trace", + pInfo->TimerHandle, + herr); return; } DeleteTimerInfo(pInfo); @@ -332,4 +337,3 @@ REGISTER_NATIVES(timernatives) {"IsServerProcessing", smn_IsServerProcessing}, {NULL, NULL} }; - diff --git a/core/vm/sp_vm_engine.cpp b/core/vm/sp_vm_engine.cpp index 7dbc9fc86..02615e262 100644 --- a/core/vm/sp_vm_engine.cpp +++ b/core/vm/sp_vm_engine.cpp @@ -90,7 +90,7 @@ const char *GetSourcePawnErrorMessage(int error) return g_ErrorMsgTable[error]; } -SourcePawnEngine::SourcePawnEngine() +SourcePawnEngine::SourcePawnEngine() : m_ExeMemory(16) { m_pDebugHook = NULL; m_CallStack = NULL; @@ -137,6 +137,26 @@ void *SourcePawnEngine::ExecAlloc(size_t size) #endif } +void *SourcePawnEngine::AllocatePageMemory(size_t size) +{ + return m_ExeMemory.Alloc(size); +} + +void SourcePawnEngine::SetReadExecute(void *ptr) +{ + m_ExeMemory.SetRE(ptr); +} + +void SourcePawnEngine::SetReadWrite(void *ptr) +{ + m_ExeMemory.SetRW(ptr); +} + +void SourcePawnEngine::FreePageMemory(void *ptr) +{ + m_ExeMemory.Free(ptr); +} + void SourcePawnEngine::ExecFree(void *address) { #if defined WIN32 diff --git a/core/vm/sp_vm_engine.h b/core/vm/sp_vm_engine.h index 4dd320d7e..5e3eee989 100644 --- a/core/vm/sp_vm_engine.h +++ b/core/vm/sp_vm_engine.h @@ -32,6 +32,15 @@ #ifndef _INCLUDE_SOURCEPAWN_VM_ENGINE_H_ #define _INCLUDE_SOURCEPAWN_VM_ENGINE_H_ +#include +/* HACK to avoid including sourcehook.h for just the SH_ASSERT definition */ +#if !defined SH_ASSERT + #define SH_ASSERT(x, info) + #include + #undef SH_ASSERT +#else + #include +#endif #include "sp_vm_api.h" #include "sp_vm_function.h" @@ -82,6 +91,10 @@ public: //ISourcePawnEngine IDebugListener *SetDebugListener(IDebugListener *pListener); unsigned int GetContextCallCount(); unsigned int GetEngineAPIVersion(); + void *AllocatePageMemory(size_t size); + void SetReadWrite(void *ptr); + void SetReadExecute(void *ptr); + void FreePageMemory(void *ptr); public: //Debugger Stuff /** * @brief Pushes a context onto the top of the call tracer. @@ -110,6 +123,7 @@ private: TracedCall *m_FreedCalls; TracedCall *m_CallStack; unsigned int m_CurChain; + SourceHook::CPageAlloc m_ExeMemory; //CFunction *m_pFreeFuncs; }; diff --git a/extensions/bintools/CallWrapper.cpp b/extensions/bintools/CallWrapper.cpp index 6a27cfa13..41392e2bf 100644 --- a/extensions/bintools/CallWrapper.cpp +++ b/extensions/bintools/CallWrapper.cpp @@ -75,7 +75,7 @@ CallWrapper::~CallWrapper() { delete [] m_Params; delete m_RetParam; - g_SPEngine->ExecFree(m_Addrs[ADDR_CODEBASE]); + g_SPEngine->FreePageMemory(m_Addrs[ADDR_CODEBASE]); } void CallWrapper::Destroy() diff --git a/extensions/bintools/jit_call.cpp b/extensions/bintools/jit_call.cpp index 112094a47..7443260ed 100644 --- a/extensions/bintools/jit_call.cpp +++ b/extensions/bintools/jit_call.cpp @@ -637,7 +637,8 @@ skip_retbuffer: if (writer.outbase == NULL) { CodeSize = writer.get_outputpos(); - writer.outbase = (jitcode_t)g_SPEngine->ExecAlloc(CodeSize); + writer.outbase = (jitcode_t)g_SPEngine->AllocatePageMemory(CodeSize); + g_SPEngine->SetReadWrite(writer.outbase); writer.outptr = writer.outbase; pWrapper->m_Addrs[ADDR_CODEBASE] = writer.outbase; g_StackAlign = (g_StackUsage) ? ((g_StackUsage & 0xFFFFFFF0) + 16) - g_StackUsage : 0; @@ -646,4 +647,5 @@ skip_retbuffer: Needs_Retbuf = false; goto jit_rewind; } + g_SPEngine->SetReadExecute(writer.outbase); } diff --git a/public/ISourceMod.h b/public/ISourceMod.h index ae5f08514..5782b7729 100644 --- a/public/ISourceMod.h +++ b/public/ISourceMod.h @@ -43,7 +43,7 @@ #include #define SMINTERFACE_SOURCEMOD_NAME "ISourceMod" -#define SMINTERFACE_SOURCEMOD_VERSION 4 +#define SMINTERFACE_SOURCEMOD_VERSION 5 /** * @brief Forward declaration of the KeyValues class. diff --git a/public/sourcepawn/sp_vm_api.h b/public/sourcepawn/sp_vm_api.h index 36fd5935e..7920188b5 100644 --- a/public/sourcepawn/sp_vm_api.h +++ b/public/sourcepawn/sp_vm_api.h @@ -41,7 +41,7 @@ #include "sp_vm_types.h" /** SourcePawn Engine API Version */ -#define SOURCEPAWN_ENGINE_API_VERSION 1 +#define SOURCEPAWN_ENGINE_API_VERSION 2 /** SourcePawn VM API Version */ #define SOURCEPAWN_VM_API_VERSION 5 @@ -740,6 +740,7 @@ namespace SourcePawn /** * @brief Allocates executable memory. + * @deprecated Use AllocPageMemory() * * @param size Size of memory to allocate. * @return Pointer to memory, NULL if allocation failed. @@ -748,6 +749,7 @@ namespace SourcePawn /** * @brief Frees executable memory. + * @deprecated Use FreePageMemory() * * @param address Address to free. */ @@ -777,6 +779,35 @@ namespace SourcePawn * @return Engine API version. */ virtual unsigned int GetEngineAPIVersion() =0; + + /** + * @brief Allocates executable memory. + * + * @param size Size of memory to allocate. + * @return Pointer to memory, NULL if allocation failed. + */ + virtual void *AllocatePageMemory(size_t size) =0; + + /** + * @brief Sets the input memory permissions to read+write. + * + * @param ptr Memory block. + */ + virtual void SetReadWrite(void *ptr) =0; + + /** + * @brief Sets the input memory permissions to read+execute. + * + * @param ptr Memory block. + */ + virtual void SetReadExecute(void *ptr) =0; + + /** + * @brief Frees executable memory. + * + * @param ptr Address to free. + */ + virtual void FreePageMemory(void *ptr) =0; }; diff --git a/sourcepawn/jit/x86/jit_x86.cpp b/sourcepawn/jit/x86/jit_x86.cpp index ec492a5b6..a01a66cd9 100644 --- a/sourcepawn/jit/x86/jit_x86.cpp +++ b/sourcepawn/jit/x86/jit_x86.cpp @@ -2380,7 +2380,8 @@ jit_rewind: /* the total codesize is now known! */ codemem = writer.get_outputpos(); - writer.outbase = (jitcode_t)engine->ExecAlloc(codemem); + writer.outbase = (jitcode_t)engine->AllocatePageMemory(codemem); + engine->SetReadWrite(writer.outbase); writer.outptr = writer.outbase; /* go back for third pass */ goto jit_rewind; @@ -2398,6 +2399,8 @@ jit_rewind: } /* Write these last because error jumps should be unpredicted, and thus forward */ WriteErrorRoutines(data, jit); + + engine->SetReadExecute(writer.outbase); } /************* @@ -2605,22 +2608,25 @@ rewind: if (jw.outbase == NULL) { /* Second pass: Actually write */ - jw.outbase = (jitcode_t)engine->ExecAlloc(jw.get_outputpos()); + jw.outbase = (jitcode_t)engine->AllocatePageMemory(jw.get_outputpos()); if (!jw.outbase) { return NULL; } + engine->SetReadWrite(jw.outbase); jw.outptr = jw.outbase; goto rewind; } - + + engine->SetReadExecute(jw.outbase); + return (SPVM_NATIVE_FUNC)jw.outbase; } void JITX86::DestroyFakeNative(SPVM_NATIVE_FUNC func) { - engine->ExecFree((void *)func); + engine->FreePageMemory(func); } const char *JITX86::GetVMName() @@ -2637,7 +2643,7 @@ int JITX86::ContextExecute(sp_context_t *ctx, uint32_t code_idx, cell_t *result) void JITX86::FreeContext(sp_context_t *ctx) { - engine->ExecFree(ctx->codebase); + engine->FreePageMemory(ctx->codebase); delete [] ctx->memory; delete [] ctx->files; delete [] ctx->lines;