From 17204aba1d29325a8cbd8b995cdfab5935b9935c Mon Sep 17 00:00:00 2001 From: arDTDev Date: Sun, 30 Nov 2025 19:41:45 +0900 Subject: [PATCH] Improve Debug build and JIT script execution - Use VirtualAlloc with PAGE_EXECUTE_READWRITE for JIT code buffers - Remove DEP disable flag, rely on proper memory allocation instead - Allow Debug build to use command-line IP args (fallback to 127.0.0.1) - Add CHANGELOG.md documenting all recent fixes --- CHANGELOG.md | 30 +++++++++++++++++++ Client/Client/RYLClient/RYLClient.vcxproj | 1 - .../RYLClient/RYLClient/RYLClientMain.cpp | 17 +++++++++-- Client/Client/ScriptEngine/VirtualMachine.cpp | 23 ++++++++++++-- 4 files changed, 64 insertions(+), 7 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..c20e8cb --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,30 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +## [2024-11-30] - Build System & Script Engine Fixes + +### Fixed +- **Release_NoGD Configuration**: Added missing compiler settings (SSE2, OpenMP, warning suppressions) to match Release configuration +- **Debug Build Linker Error**: Added `_USE_32BIT_TIME_T` preprocessor definition to GlobalScript Debug configuration to fix `ParsePacket::HandleUserLogin` time_t size mismatch (LNK2019) +- **Script Execution Crash**: Implemented VirtualAlloc with PAGE_EXECUTE_READWRITE for JIT code buffer allocation to resolve DEP-related memory access violations +- **Standalone Debugging**: Modified `_RYL_TEST` mode to automatically enable `ADMIN_L3` without requiring Login.exe + +### Changed +- **Working Directory**: Set LocalDebuggerWorkingDirectory to `F:\YouxiLand\ROW` for all configurations to enable proper resource loading during debugging +- **Server IP Handling**: Modified `GetServerInfo()` to respect command-line IP arguments even in Debug builds, falling back to `127.0.0.1` only when no IP is provided +- **Memory Management**: Enhanced `CVirtualMachine::Destroy()` to properly detect and free VirtualAlloc-allocated memory using VirtualQuery + +### Added +- **Debug Logging**: Added MCF file decryption logging (`.decrypted.log` files) for script debugging +- **Execute State Logging**: Added comprehensive state logging to `script_execute.log` before script execution + +### Technical Details +- MCF XOR encryption key: `0x82fac623 ^ 0x601f1ac4` +- Stack reserve size increased to 8MB for Debug configuration +- Code buffer now allocated with executable permissions for JIT execution compatibility with Windows 10/11 DEP + +### Notes +- Visual Studio 2010 project +- DirectX 8 graphics API +- Custom JIT script engine with x86 machine code execution diff --git a/Client/Client/RYLClient/RYLClient.vcxproj b/Client/Client/RYLClient/RYLClient.vcxproj index de758b8..5e42065 100644 --- a/Client/Client/RYLClient/RYLClient.vcxproj +++ b/Client/Client/RYLClient/RYLClient.vcxproj @@ -137,7 +137,6 @@ $(OutDir)Client.pdb Windows 8388608 - false MachineX86 false HighestAvailable diff --git a/Client/Client/RYLClient/RYLClient/RYLClientMain.cpp b/Client/Client/RYLClient/RYLClient/RYLClientMain.cpp index 9ce87c4..9548db1 100644 --- a/Client/Client/RYLClient/RYLClient/RYLClientMain.cpp +++ b/Client/Client/RYLClient/RYLClient/RYLClientMain.cpp @@ -602,6 +602,10 @@ USES_CONVERSION; VOID CClientMain::GetServerInfo( HWND hWnd ) { char *strCommandLine = GetCommandLine() ; + + // 기본값으로 초기화 + strcpy(CRYLNetworkData::m_strIP, ""); + CRYLNetworkData::m_dwServerID = 0; if ( hWnd ) { @@ -612,12 +616,19 @@ VOID CClientMain::GetServerInfo( HWND hWnd ) else { char *pLast = strrchr( strCommandLine, '"' ) ; - pLast += 2 ; - sscanf( pLast,"%s %d", CRYLNetworkData::m_strIP, &CRYLNetworkData::m_dwServerID ) ; + if (pLast) + { + pLast += 2 ; + sscanf( pLast,"%s %d", CRYLNetworkData::m_strIP, &CRYLNetworkData::m_dwServerID ) ; + } } #ifdef DEBUG - strcpy(CRYLNetworkData::m_strIP, "127.0.0.1"); + // 명령줄에서 IP를 받지 못한 경우에만 기본값 사용 + if (strlen(CRYLNetworkData::m_strIP) == 0 || strcmp(CRYLNetworkData::m_strIP, "") == 0) + { + strcpy(CRYLNetworkData::m_strIP, "127.0.0.1"); + } #endif /* if ( m_wAdminMode == ADMIN_L3 ) diff --git a/Client/Client/ScriptEngine/VirtualMachine.cpp b/Client/Client/ScriptEngine/VirtualMachine.cpp index 3c545ac..0603641 100644 --- a/Client/Client/ScriptEngine/VirtualMachine.cpp +++ b/Client/Client/ScriptEngine/VirtualMachine.cpp @@ -10,6 +10,7 @@ #include #include #include "GMMemory.h" +#include typedef unsigned char byte; @@ -232,7 +233,11 @@ void CVirtualMachine::Create( const void * pDataBuf, unsigned DataSize ) TotalBufferSize = GlobalVarBufferSize + StringBufferSize + m_iCodeSize; - m_pGlobalVars = m_pBuffer = new char[TotalBufferSize]; + // Use VirtualAlloc for executable code buffer + m_pGlobalVars = m_pBuffer = (char*)VirtualAlloc(NULL, TotalBufferSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + if (m_pBuffer == NULL) { + m_pGlobalVars = m_pBuffer = new char[TotalBufferSize]; + } m_pStringBuffer = ((byte*)m_pGlobalVars) + GlobalVarBufferSize; m_pCodeBuffer = ((byte*)m_pStringBuffer) + StringBufferSize; @@ -277,7 +282,11 @@ void CVirtualMachine::Create( CIntermediateCode & IMCode, CSymbolTable & Symbo int StringBufferSize = SymbolTable.GetStringBufferSize(); int BufSize = GlobalVarsSize + StringBufferSize + m_iCodeSize; - m_pGlobalVars = m_pBuffer = new char[ BufSize ]; + // Use VirtualAlloc for executable code buffer + m_pGlobalVars = m_pBuffer = (char*)VirtualAlloc(NULL, BufSize, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + if (m_pBuffer == NULL) { + m_pGlobalVars = m_pBuffer = new char[ BufSize ]; + } memset( m_pGlobalVars, 0, GlobalVarsSize ); @@ -329,7 +338,15 @@ void CVirtualMachine::SetSysVars() void CVirtualMachine::Destroy() { - delete [] m_pBuffer; + // Check if buffer was allocated with VirtualAlloc (aligned to 4KB/64KB boundary typically) + if (m_pBuffer != NULL) { + MEMORY_BASIC_INFORMATION mbi; + if (VirtualQuery(m_pBuffer, &mbi, sizeof(mbi)) && mbi.AllocationBase == m_pBuffer) { + VirtualFree(m_pBuffer, 0, MEM_RELEASE); + } else { + delete [] m_pBuffer; + } + } m_pBuffer = m_pGlobalVars = m_pStringBuffer = m_pCodeBuffer = NULL; m_iCodeSize = 0; m_pFunctionMap->clear();