Skip to content

Commit 3530317

Browse files
committed
Addendum to 36ec08c (CEF rework #5) for some more potential mem leaks
1 parent 744b0cb commit 3530317

File tree

6 files changed

+77
-32
lines changed

6 files changed

+77
-32
lines changed

Client/cefweb/CAjaxResourceHandler.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ void CAjaxResourceHandler::SetResponse(std::string data)
3636
m_strResponse = std::move(data);
3737
m_bHasData = true;
3838

39+
// Clear request data to free memory as it's no longer needed
40+
m_vecGetData.clear();
41+
m_vecGetData.shrink_to_fit();
42+
m_vecPostData.clear();
43+
m_vecPostData.shrink_to_fit();
44+
3945
if (!m_callback)
4046
return;
4147

Client/cefweb/CWebCore.cpp

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@
2727
#pragma comment(lib, "cef_sandbox.lib")
2828
#endif
2929

30+
CWebCore::EventEntry::EventEntry(const std::function<void()>& callback_, CWebView* pWebView_) : callback(callback_), pWebView(pWebView_) {}
31+
32+
#ifdef MTA_DEBUG
33+
CWebCore::EventEntry::EventEntry(const std::function<void()>& callback_, CWebView* pWebView_, const SString& name_) : callback(callback_), pWebView(pWebView_), name(name_) {}
34+
#endif
35+
36+
CWebCore::TaskEntry::TaskEntry(std::function<void(bool)> callback, CWebView* webView) : task(callback), webView(webView) {}
37+
3038
CWebCore::CWebCore()
3139
{
3240
m_pRequestsGUI = nullptr;
@@ -363,7 +371,7 @@ void CWebCore::AddEventToEventQueue(std::function<void()> event, CWebView* pWebV
363371
if (pWebView && pWebView->IsBeingDestroyed())
364372
return;
365373

366-
std::lock_guard<std::mutex> lock(m_EventQueueMutex);
374+
std::scoped_lock lock(m_EventQueueMutex);
367375

368376
// Prevent unbounded queue growth - drop oldest events if queue is too large
369377
if (m_EventQueue.size() >= MAX_EVENT_QUEUE_SIZE)
@@ -386,7 +394,7 @@ void CWebCore::AddEventToEventQueue(std::function<void()> event, CWebView* pWebV
386394

387395
void CWebCore::RemoveWebViewEvents(CWebView* pWebView)
388396
{
389-
std::lock_guard<std::mutex> lock(m_EventQueueMutex);
397+
std::scoped_lock lock(m_EventQueueMutex);
390398

391399
for (auto iter = m_EventQueue.begin(); iter != m_EventQueue.end();)
392400
{
@@ -401,12 +409,16 @@ void CWebCore::DoEventQueuePulse()
401409
{
402410
std::list<EventEntry> eventQueue;
403411
{
404-
std::lock_guard<std::mutex> lock(m_EventQueueMutex);
412+
std::scoped_lock lock(m_EventQueueMutex);
405413
std::swap(eventQueue, m_EventQueue);
406414
}
407415

408416
for (auto& event : eventQueue)
409417
{
418+
// Skip event if the associated WebView is being destroyed
419+
if (event.pWebView && event.pWebView->IsBeingDestroyed())
420+
continue;
421+
410422
event.callback();
411423
}
412424

@@ -473,13 +485,20 @@ void CWebCore::DoTaskQueuePulse()
473485

474486
for (TaskEntry& entry : taskQueue)
475487
{
488+
// Abort task if the associated WebView is being destroyed
489+
if (entry.webView && entry.webView->IsBeingDestroyed())
490+
{
491+
entry.task(true);
492+
continue;
493+
}
494+
476495
entry.task(false);
477496
}
478497
}
479498

480499
eURLState CWebCore::GetDomainState(const SString& strURL, bool bOutputDebug)
481500
{
482-
std::lock_guard<std::recursive_mutex> lock(m_FilterMutex);
501+
std::scoped_lock lock(m_FilterMutex);
483502

484503
// Initialize wildcard whitelist (be careful with modifying) | Todo: Think about the following
485504
static constexpr const char* wildcardWhitelist[] = {"*.googlevideo.com", "*.google.com", "*.youtube.com", "*.ytimg.com",
@@ -491,8 +510,7 @@ eURLState CWebCore::GetDomainState(const SString& strURL, bool bOutputDebug)
491510
return eURLState::WEBPAGE_ALLOWED;
492511
}
493512

494-
google::dense_hash_map<SString, WebFilterPair>::iterator iter = m_Whitelist.find(strURL);
495-
if (iter != m_Whitelist.end())
513+
if (auto iter = m_Whitelist.find(strURL); iter != m_Whitelist.end())
496514
{
497515
if (iter->second.first == true)
498516
return eURLState::WEBPAGE_ALLOWED;
@@ -583,7 +601,7 @@ void CWebCore::InitialiseWhiteAndBlacklist(bool bAddHardcoded, bool bAddDynamic)
583601

584602
void CWebCore::AddAllowedPage(const SString& strURL, eWebFilterType filterType)
585603
{
586-
std::lock_guard<std::recursive_mutex> lock(m_FilterMutex);
604+
std::scoped_lock lock(m_FilterMutex);
587605

588606
// Prevent unbounded whitelist growth - remove old REQUEST entries if limit reached
589607
if (m_Whitelist.size() >= 50000)
@@ -603,7 +621,7 @@ void CWebCore::AddAllowedPage(const SString& strURL, eWebFilterType filterType)
603621

604622
void CWebCore::AddBlockedPage(const SString& strURL, eWebFilterType filterType)
605623
{
606-
std::lock_guard<std::recursive_mutex> lock(m_FilterMutex);
624+
std::scoped_lock lock(m_FilterMutex);
607625

608626
// Prevent unbounded whitelist growth - remove old REQUEST entries if limit reached
609627
if (m_Whitelist.size() >= 50000)
@@ -623,6 +641,13 @@ void CWebCore::AddBlockedPage(const SString& strURL, eWebFilterType filterType)
623641

624642
void CWebCore::RequestPages(const std::vector<SString>& pages, WebRequestCallback* pCallback)
625643
{
644+
if (m_PendingRequests.size() >= MAX_PENDING_REQUESTS)
645+
{
646+
if (pCallback)
647+
(*pCallback)(false, std::unordered_set<SString>(pages.begin(), pages.end()));
648+
return;
649+
}
650+
626651
// Add to pending pages queue
627652
bool bNewItem = false;
628653
for (const auto& page : pages)
@@ -631,8 +656,9 @@ void CWebCore::RequestPages(const std::vector<SString>& pages, WebRequestCallbac
631656
if (status == eURLState::WEBPAGE_ALLOWED || status == eURLState::WEBPAGE_DISALLOWED)
632657
continue;
633658

634-
m_PendingRequests.insert(page);
635-
bNewItem = true;
659+
const auto [iter, inserted] = m_PendingRequests.insert(page);
660+
if (inserted)
661+
bNewItem = true;
636662
}
637663

638664
if (bNewItem)

Client/cefweb/CWebCore.h

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#define MAX_EVENT_QUEUE_SIZE 10000
2424
#define MAX_TASK_QUEUE_SIZE 1000
2525
#define MAX_WHITELIST_SIZE 50000
26+
#define MAX_PENDING_REQUESTS 100
2627
#define GetNextSibling(hwnd) GetWindow(hwnd, GW_HWNDNEXT) // Re-define the conflicting macro
2728
#define GetFirstChild(hwnd) GetTopWindow(hwnd)
2829

@@ -36,23 +37,23 @@ class CWebCore : public CWebCoreInterface
3637
struct EventEntry
3738
{
3839
std::function<void()> callback;
39-
CWebView* pWebView;
40+
CefRefPtr<CWebView> pWebView;
4041
#ifdef MTA_DEBUG
4142
SString name;
4243
#endif
4344

44-
EventEntry(const std::function<void()>& callback_, CWebView* pWebView_) : callback(callback_), pWebView(pWebView_) {}
45+
EventEntry(const std::function<void()>& callback_, CWebView* pWebView_);
4546
#ifdef MTA_DEBUG
46-
EventEntry(const std::function<void()>& callback_, CWebView* pWebView_, const SString& name_) : callback(callback_), pWebView(pWebView_), name(name_) {}
47+
EventEntry(const std::function<void()>& callback_, CWebView* pWebView_, const SString& name_);
4748
#endif
4849
};
4950

5051
struct TaskEntry
5152
{
5253
std::packaged_task<void(bool)> task;
53-
CWebView* webView;
54+
CefRefPtr<CWebView> webView;
5455

55-
TaskEntry(std::function<void(bool)> callback, CWebView* webView) : task(callback), webView(webView) {}
56+
TaskEntry(std::function<void(bool)> callback, CWebView* webView);
5657
};
5758

5859
public:

Client/cefweb/CWebView.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,9 @@ CWebView::CWebView(bool bIsLocal, CWebBrowserItem* pWebBrowserRenderItem, bool b
2525
m_bIsLocal = bIsLocal;
2626
m_bIsTransparent = bTransparent;
2727
m_pWebBrowserRenderItem = pWebBrowserRenderItem;
28+
if (m_pWebBrowserRenderItem)
29+
m_pWebBrowserRenderItem->AddRef();
30+
2831
m_pEventsInterface = nullptr;
2932
m_bBeingDestroyed = false;
3033
m_fVolume = 1.0f;
@@ -47,6 +50,12 @@ CWebView::~CWebView()
4750
}
4851
}
4952

53+
if (m_pWebBrowserRenderItem)
54+
{
55+
m_pWebBrowserRenderItem->Release();
56+
m_pWebBrowserRenderItem = nullptr;
57+
}
58+
5059
// Make sure we don't dead lock the CEF render thread
5160
ResumeCefThread();
5261

@@ -280,7 +289,7 @@ void CWebView::ClearTexture()
280289

281290
void CWebView::UpdateTexture()
282291
{
283-
const std::lock_guard lock(m_RenderData.dataMutex);
292+
const std::scoped_lock lock(m_RenderData.dataMutex);
284293

285294
// Validate render item exists before accessing
286295
if (!m_pWebBrowserRenderItem) [[unlikely]]
@@ -714,23 +723,23 @@ void CWebView::GetSourceCode(const std::function<void(const std::string& code)>&
714723
class MyStringVisitor : public CefStringVisitor
715724
{
716725
private:
717-
CWebView* webView;
726+
CefRefPtr<CWebView> webView;
718727
std::function<void(const std::string&)> callback;
719728

720729
public:
721730
MyStringVisitor(CWebView* webView_, const std::function<void(const std::string&)>& callback_) : webView(webView_), callback(callback_) {}
722731

723732
virtual void Visit(const CefString& code) override
724733
{
725-
// Avoid UAF
734+
// Check if webview is being destroyed to prevent UAF
726735
if (webView->IsBeingDestroyed())
727736
return;
728737

729738
// Limit to 2MiB for now to prevent freezes (TODO: Optimize that and increase later)
730739
if (code.size() <= 2097152)
731740
{
732741
// Call callback on main thread
733-
g_pCore->GetWebCore()->AddEventToEventQueue(std::bind(callback, code), webView, "GetSourceCode_Visit");
742+
g_pCore->GetWebCore()->AddEventToEventQueue(std::bind(callback, code), webView.get(), "GetSourceCode_Visit");
734743
}
735744
}
736745

@@ -783,8 +792,8 @@ bool CWebView::GetFullPathFromLocal(SString& strPath)
783792

784793
bool CWebView::RegisterAjaxHandler(const SString& strURL)
785794
{
786-
auto result = m_AjaxHandlers.insert(strURL);
787-
return result.second;
795+
auto [iter, inserted] = m_AjaxHandlers.insert(strURL);
796+
return inserted;
788797
}
789798

790799
bool CWebView::UnregisterAjaxHandler(const SString& strURL)

Client/cefweb/CWebsiteRequests.cpp

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,8 @@ CWebsiteRequests::CWebsiteRequests()
6363

6464
CWebsiteRequests::~CWebsiteRequests()
6565
{
66-
delete m_pLabel1;
67-
delete m_pLabel2;
68-
delete m_pAddressMemo;
69-
delete m_pCheckRemember;
70-
delete m_pButtonAllow;
71-
delete m_pButtonDeny;
72-
delete m_pWindow;
66+
if (m_pWindow)
67+
g_pCore->GetGUI()->DestroyElementRecursive(m_pWindow);
7368
}
7469

7570
void CWebsiteRequests::Show()
@@ -126,8 +121,11 @@ void CWebsiteRequests::Callback(bool bAllow, const std::unordered_set<SString>&
126121
bool CWebsiteRequests::OnAllowButtonClick(CGUIElement* pElement)
127122
{
128123
Hide();
129-
const auto pWebCore = g_pCore->GetWebCore();
130-
const auto requests = pWebCore ? pWebCore->AllowPendingPages(m_pCheckRemember->GetSelected()) : std::unordered_set<SString>();
124+
std::unordered_set<SString> requests;
125+
if (auto pWebCore = g_pCore->GetWebCore(); pWebCore)
126+
{
127+
requests = pWebCore->AllowPendingPages(m_pCheckRemember->GetSelected());
128+
}
131129
Callback(true, requests);
132130

133131
return true;
@@ -136,8 +134,11 @@ bool CWebsiteRequests::OnAllowButtonClick(CGUIElement* pElement)
136134
bool CWebsiteRequests::OnDenyButtonClick(CGUIElement* pElement)
137135
{
138136
Hide();
139-
const auto pWebCore = g_pCore->GetWebCore();
140-
const auto requests = pWebCore ? pWebCore->DenyPendingPages() : std::unordered_set<SString>();
137+
std::unordered_set<SString> requests;
138+
if (auto pWebCore = g_pCore->GetWebCore(); pWebCore)
139+
{
140+
requests = pWebCore->DenyPendingPages();
141+
}
141142
Callback(false, requests);
142143

143144
return true;

Client/sdk/core/CRenderItemManagerInterface.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
*
1010
*****************************************************************************/
1111

12+
#pragma once
13+
1214
#include <CVector.h>
1315
#include <CVector2D.h>
1416

0 commit comments

Comments
 (0)