Skip to content

Commit 33178bc

Browse files
authored
Merge branch 'master' into fix/improve-aclrequest-detection
2 parents 1bd9f79 + 04f0d4c commit 33178bc

File tree

239 files changed

+120864
-104938
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

239 files changed

+120864
-104938
lines changed

Client/cefweb/CAjaxResourceHandler.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ CAjaxResourceHandler::CAjaxResourceHandler(std::vector<SString>& vecGet, std::ve
1818
{
1919
}
2020

21+
CAjaxResourceHandler::~CAjaxResourceHandler()
22+
{
23+
// Ensure callback is released if handler is destroyed before completion
24+
if (m_callback)
25+
{
26+
m_callback = nullptr;
27+
}
28+
}
29+
2130
std::vector<SString>& CAjaxResourceHandler::GetGetData()
2231
{
2332
return m_vecGetData;
@@ -34,12 +43,18 @@ void CAjaxResourceHandler::SetResponse(const SString& data)
3443
m_bHasData = true;
3544

3645
if (m_callback)
46+
{
3747
m_callback->Continue();
48+
// Release callback to prevent memory leak
49+
m_callback = nullptr;
50+
}
3851
}
3952

4053
// CefResourceHandler implementation
4154
void CAjaxResourceHandler::Cancel()
4255
{
56+
// Release callback reference on cancellation to prevent memory leak
57+
m_callback = nullptr;
4358
}
4459

4560
void CAjaxResourceHandler::GetResponseHeaders(CefRefPtr<CefResponse> response, int64& response_length, CefString& redirectUrl)

Client/cefweb/CAjaxResourceHandler.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class CAjaxResourceHandler : public CefResourceHandler, public CAjaxResourceHand
2020
{
2121
public:
2222
CAjaxResourceHandler(std::vector<SString>& vecGet, std::vector<SString>& vecPost, const CefString& mimeType);
23+
virtual ~CAjaxResourceHandler();
2324

2425
virtual std::vector<SString>& GetGetData() override;
2526
virtual std::vector<SString>& GetPostData() override;

Client/cefweb/CWebCore.cpp

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,13 +109,22 @@ void CWebCore::DestroyWebView(CWebViewInterface* pWebViewInterface)
109109
CefRefPtr<CWebView> pWebView = dynamic_cast<CWebView*>(pWebViewInterface);
110110
if (pWebView)
111111
{
112+
// Mark as being destroyed to prevent new events/tasks
113+
pWebView->SetBeingDestroyed(true);
114+
112115
// Ensure that no attached events or tasks are in the queue
113116
RemoveWebViewEvents(pWebView.get());
114117
RemoveWebViewTasks(pWebView.get());
115118

119+
// Remove from list before closing to break reference cycles early
116120
m_WebViews.remove(pWebView);
117-
// pWebView->Release(); // Do not release since other references get corrupted then
121+
122+
// CloseBrowser will eventually trigger OnBeforeClose which clears m_pWebView
123+
// This breaks the circular reference: CWebView -> CefBrowser -> CWebView
118124
pWebView->CloseBrowser();
125+
126+
// Note: Do not call Release() - let CefRefPtr manage the lifecycle
127+
// The circular reference is broken via OnBeforeClose setting m_pWebView = nullptr
119128
}
120129
}
121130

@@ -164,6 +173,18 @@ void CWebCore::AddEventToEventQueue(std::function<void()> event, CWebView* pWebV
164173

165174
std::lock_guard<std::mutex> lock(m_EventQueueMutex);
166175

176+
// Prevent unbounded queue growth - drop oldest events if queue is too large
177+
if (m_EventQueue.size() >= MAX_EVENT_QUEUE_SIZE)
178+
{
179+
// Log warning even in release builds as this indicates a serious issue
180+
g_pCore->GetConsole()->Printf("WARNING: Browser event queue size limit reached (%d), dropping oldest events", MAX_EVENT_QUEUE_SIZE);
181+
182+
// Remove oldest 10% of events to make room
183+
auto removeCount = MAX_EVENT_QUEUE_SIZE / 10;
184+
for (size_t i = 0; i < removeCount && !m_EventQueue.empty(); ++i)
185+
m_EventQueue.pop_front();
186+
}
187+
167188
#ifndef MTA_DEBUG
168189
m_EventQueue.push_back(EventEntry(event, pWebView));
169190
#else
@@ -215,6 +236,22 @@ void CWebCore::WaitForTask(std::function<void(bool)> task, CWebView* webView)
215236
std::future<void> result;
216237
{
217238
std::scoped_lock lock(m_TaskQueueMutex);
239+
240+
// Prevent unbounded queue growth - if queue is too large, oldest tasks will be dropped during pulse
241+
if (m_TaskQueue.size() >= MAX_TASK_QUEUE_SIZE)
242+
{
243+
#ifdef MTA_DEBUG
244+
g_pCore->GetConsole()->Printf("Warning: Task queue size limit reached (%d), task will be aborted", MAX_TASK_QUEUE_SIZE);
245+
#endif
246+
// Must still queue the task to fulfill the future, but it will be aborted during processing
247+
// Removing oldest task to make room
248+
if (!m_TaskQueue.empty())
249+
{
250+
m_TaskQueue.front().task(true); // Abort oldest task
251+
m_TaskQueue.pop_front();
252+
}
253+
}
254+
218255
m_TaskQueue.emplace_back(TaskEntry{task, webView});
219256
result = m_TaskQueue.back().task.get_future();
220257
}
@@ -358,13 +395,39 @@ void CWebCore::AddAllowedPage(const SString& strURL, eWebFilterType filterType)
358395
{
359396
std::lock_guard<std::recursive_mutex> lock(m_FilterMutex);
360397

398+
// Prevent unbounded whitelist growth - remove old REQUEST entries if limit reached
399+
if (m_Whitelist.size() >= MAX_WHITELIST_SIZE)
400+
{
401+
// Remove WEBFILTER_REQUEST entries (temporary session entries)
402+
for (auto iter = m_Whitelist.begin(); iter != m_Whitelist.end();)
403+
{
404+
if (iter->second.second == eWebFilterType::WEBFILTER_REQUEST)
405+
m_Whitelist.erase(iter++);
406+
else
407+
++iter;
408+
}
409+
}
410+
361411
m_Whitelist[strURL] = std::pair<bool, eWebFilterType>(true, filterType);
362412
}
363413

364414
void CWebCore::AddBlockedPage(const SString& strURL, eWebFilterType filterType)
365415
{
366416
std::lock_guard<std::recursive_mutex> lock(m_FilterMutex);
367417

418+
// Prevent unbounded whitelist growth - remove old REQUEST entries if limit reached
419+
if (m_Whitelist.size() >= MAX_WHITELIST_SIZE)
420+
{
421+
// Remove WEBFILTER_REQUEST entries (temporary session entries)
422+
for (auto iter = m_Whitelist.begin(); iter != m_Whitelist.end();)
423+
{
424+
if (iter->second.second == eWebFilterType::WEBFILTER_REQUEST)
425+
m_Whitelist.erase(iter++);
426+
else
427+
++iter;
428+
}
429+
}
430+
368431
m_Whitelist[strURL] = std::pair<bool, eWebFilterType>(false, filterType);
369432
}
370433

Client/cefweb/CWebCore.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
#define MTA_BROWSERDATA_PATH "mta/cef/browserdata.xml"
2121
#define BROWSER_LIST_UPDATE_INTERVAL (24*60*60)
2222
#define BROWSER_UPDATE_URL "https://cef.multitheftauto.com/get.php"
23+
#define MAX_EVENT_QUEUE_SIZE 10000
24+
#define MAX_TASK_QUEUE_SIZE 1000
25+
#define MAX_WHITELIST_SIZE 50000
2326
#define GetNextSibling(hwnd) GetWindow(hwnd, GW_HWNDNEXT) // Re-define the conflicting macro
2427
#define GetFirstChild(hwnd) GetTopWindow(hwnd)
2528

Client/cefweb/CWebView.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,15 @@ CWebView::~CWebView()
4444
// Make sure we don't dead lock the CEF render thread
4545
ResumeCefThread();
4646

47-
// Ensure that CefRefPtr::~CefRefPtr doesn't try to release it twice (it has already been released in CWebView::OnBeforeClose)
48-
m_pWebView = nullptr;
47+
// Clean up AJAX handlers to prevent accumulation
48+
m_AjaxHandlers.clear();
49+
50+
// Break circular reference: ensure browser reference is cleared
51+
// This is to prevent memory leaks from CWebView <-> CefBrowser cycles
52+
if (m_pWebView)
53+
{
54+
m_pWebView = nullptr;
55+
}
4956

5057
OutputDebugLine("CWebView::~CWebView");
5158
}
@@ -83,6 +90,9 @@ void CWebView::CloseBrowser()
8390
// Make sure we don't dead lock the CEF render thread
8491
ResumeCefThread();
8592

93+
// Clear AJAX handlers early to prevent late event processing
94+
m_AjaxHandlers.clear();
95+
8696
if (m_pWebView)
8797
m_pWebView->GetHost()->CloseBrowser(true);
8898
}
@@ -500,8 +510,12 @@ bool CWebView::HasAjaxHandler(const SString& strURL)
500510

501511
void CWebView::HandleAjaxRequest(const SString& strURL, CAjaxResourceHandler* pHandler)
502512
{
503-
auto func = std::bind(&CWebBrowserEventsInterface::Events_OnAjaxRequest, m_pEventsInterface, pHandler, strURL);
504-
g_pCore->GetWebCore()->AddEventToEventQueue(func, this, "AjaxResourceRequest");
513+
// Only queue event if not being destroyed to prevent UAF
514+
if (!m_bBeingDestroyed)
515+
{
516+
auto func = std::bind(&CWebBrowserEventsInterface::Events_OnAjaxRequest, m_pEventsInterface, pHandler, strURL);
517+
g_pCore->GetWebCore()->AddEventToEventQueue(func, this, "AjaxResourceRequest");
518+
}
505519
}
506520

507521
bool CWebView::ToggleDevTools(bool visible)
@@ -719,6 +733,8 @@ void CWebView::OnPaint(CefRefPtr<CefBrowser> browser, CefRenderHandler::PaintEle
719733
m_RenderData.width = width;
720734
m_RenderData.height = height;
721735
m_RenderData.dirtyRects = dirtyRects;
736+
// Prevent vector capacity growth memory leak - shrink excess capacity
737+
m_RenderData.dirtyRects.shrink_to_fit();
722738
m_RenderData.changed = true;
723739

724740
// Wait for the main thread to handle drawing the texture

Client/core/CAdditionalVertexStreamManager.cpp

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "StdInc.h"
1313
#include "CAdditionalVertexStreamManager.h"
1414
#include <limits>
15+
#include <mutex>
1516

1617
CAdditionalVertexStreamManager* CAdditionalVertexStreamManager::ms_Singleton = nullptr;
1718

@@ -75,6 +76,8 @@ namespace
7576
STriKey key = {a, b, c};
7677
return key;
7778
}
79+
80+
std::mutex g_singletonMutex;
7881
} // namespace
7982

8083
///////////////////////////////////////////////////////////////
@@ -119,23 +122,26 @@ CAdditionalVertexStreamManager::~CAdditionalVertexStreamManager()
119122
///////////////////////////////////////////////////////////////
120123
CAdditionalVertexStreamManager* CAdditionalVertexStreamManager::GetSingleton()
121124
{
125+
std::lock_guard<std::mutex> guard(g_singletonMutex);
122126
if (!ms_Singleton)
123127
ms_Singleton = new CAdditionalVertexStreamManager();
124128
return ms_Singleton;
125129
}
126130

127-
CAdditionalVertexStreamManager* CAdditionalVertexStreamManager::GetExistingSingleton() noexcept
131+
CAdditionalVertexStreamManager* CAdditionalVertexStreamManager::GetExistingSingleton()
128132
{
133+
std::lock_guard<std::mutex> guard(g_singletonMutex);
129134
return ms_Singleton;
130135
}
131136

132137
void CAdditionalVertexStreamManager::DestroySingleton()
133138
{
134-
if (ms_Singleton)
135-
{
136-
delete ms_Singleton;
137-
ms_Singleton = nullptr;
138-
}
139+
std::lock_guard<std::mutex> guard(g_singletonMutex);
140+
if (!ms_Singleton)
141+
return;
142+
143+
delete ms_Singleton;
144+
ms_Singleton = nullptr;
139145
}
140146

141147
///////////////////////////////////////////////////////////////
@@ -259,7 +265,14 @@ bool CAdditionalVertexStreamManager::SetAdditionalVertexStream(SCurrentStateInfo
259265
if (FAILED(m_pDevice->GetVertexDeclaration(&pPreviousDecl)))
260266
return false;
261267

262-
if (FAILED(g_pProxyDevice->SetVertexDeclaration(pAdditionalInfo->pVertexDeclaration)))
268+
CScopedActiveProxyDevice proxyDevice;
269+
if (!proxyDevice)
270+
{
271+
SAFE_RELEASE(pPreviousDecl);
272+
return false;
273+
}
274+
275+
if (FAILED(proxyDevice->SetVertexDeclaration(pAdditionalInfo->pVertexDeclaration)))
263276
{
264277
SAFE_RELEASE(pPreviousDecl);
265278
return false;
@@ -268,7 +281,7 @@ bool CAdditionalVertexStreamManager::SetAdditionalVertexStream(SCurrentStateInfo
268281
uint OffsetInBytes = ConvertPTOffset(state.stream1.OffsetInBytes);
269282
if (FAILED(m_pDevice->SetStreamSource(2, pAdditionalInfo->pStreamData, OffsetInBytes, pAdditionalInfo->Stride)))
270283
{
271-
g_pProxyDevice->SetVertexDeclaration(pPreviousDecl);
284+
proxyDevice->SetVertexDeclaration(pPreviousDecl);
272285
SAFE_RELEASE(pPreviousDecl);
273286
return false;
274287
}
@@ -298,7 +311,9 @@ void CAdditionalVertexStreamManager::MaybeUnsetAdditionalVertexStream()
298311
if (bDeviceOperational)
299312
{
300313
// Set prev declaration
301-
g_pProxyDevice->SetVertexDeclaration(m_pOldVertexDeclaration);
314+
CScopedActiveProxyDevice proxyDevice;
315+
if (proxyDevice)
316+
proxyDevice->SetVertexDeclaration(m_pOldVertexDeclaration);
302317

303318
// Unset additional stream
304319
m_pDevice->SetStreamSource(2, nullptr, 0, 0);

Client/core/CAdditionalVertexStreamManager.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class CAdditionalVertexStreamManager
8484
void OnVertexBufferRangeInvalidated(IDirect3DVertexBuffer9* pStreamData, uint Offset, uint Size);
8585

8686
static CAdditionalVertexStreamManager* GetSingleton();
87-
static CAdditionalVertexStreamManager* GetExistingSingleton() noexcept;
87+
static CAdditionalVertexStreamManager* GetExistingSingleton();
8888
static void DestroySingleton();
8989

9090
protected:

0 commit comments

Comments
 (0)