Remove NoDestructor usage in timer classes
Add static methods to initialize/destroy 2 different timer classes. This
lets FPDF_DestroyLibrary() free more memory and work as it was
originally intended.
Bug: pdfium:1876
Change-Id: I8de78e10ebcdd9dabd168b1dc66619f402fca135
Reviewed-on: https://pdfium-review.googlesource.com/c/pdfium/+/113112
Reviewed-by: Tom Sepez <tsepez@chromium.org>
Commit-Queue: Lei Zhang <thestig@chromium.org>
diff --git a/core/fxcrt/cfx_timer.cpp b/core/fxcrt/cfx_timer.cpp
index 744b1eb..5f2a931 100644
--- a/core/fxcrt/cfx_timer.cpp
+++ b/core/fxcrt/cfx_timer.cpp
@@ -9,18 +9,26 @@
#include <map>
#include "third_party/base/check.h"
-#include "third_party/base/no_destructor.h"
namespace {
using TimerMap = std::map<int32_t, CFX_Timer*>;
-TimerMap& GetPWLTimerMap() {
- static pdfium::base::NoDestructor<TimerMap> timer_map;
- return *timer_map;
-}
+TimerMap* g_pwl_timer_map = nullptr;
} // namespace
+// static
+void CFX_Timer::InitializeGlobals() {
+ CHECK(!g_pwl_timer_map);
+ g_pwl_timer_map = new TimerMap();
+}
+
+// static
+void CFX_Timer::DestroyGlobals() {
+ delete g_pwl_timer_map;
+ g_pwl_timer_map = nullptr;
+}
+
CFX_Timer::CFX_Timer(HandlerIface* pHandlerIface,
CallbackIface* pCallbackIface,
int32_t nInterval)
@@ -29,13 +37,13 @@
if (m_pHandlerIface) {
m_nTimerID = m_pHandlerIface->SetTimer(nInterval, TimerProc);
if (HasValidID())
- GetPWLTimerMap()[m_nTimerID] = this;
+ (*g_pwl_timer_map)[m_nTimerID] = this;
}
}
CFX_Timer::~CFX_Timer() {
if (HasValidID()) {
- GetPWLTimerMap().erase(m_nTimerID);
+ g_pwl_timer_map->erase(m_nTimerID);
if (m_pHandlerIface)
m_pHandlerIface->KillTimer(m_nTimerID);
}
@@ -43,7 +51,8 @@
// static
void CFX_Timer::TimerProc(int32_t idEvent) {
- auto it = GetPWLTimerMap().find(idEvent);
- if (it != GetPWLTimerMap().end())
+ auto it = g_pwl_timer_map->find(idEvent);
+ if (it != g_pwl_timer_map->end()) {
it->second->m_pCallbackIface->OnTimerFired();
+ }
}
diff --git a/core/fxcrt/cfx_timer.h b/core/fxcrt/cfx_timer.h
index 24ed296..e8be792 100644
--- a/core/fxcrt/cfx_timer.h
+++ b/core/fxcrt/cfx_timer.h
@@ -35,6 +35,9 @@
virtual void OnTimerFired() = 0;
};
+ static void InitializeGlobals();
+ static void DestroyGlobals();
+
CFX_Timer(HandlerIface* pHandlerIface,
CallbackIface* pCallbackIface,
int32_t nInterval);
diff --git a/core/fxcrt/cfx_timer_unittest.cpp b/core/fxcrt/cfx_timer_unittest.cpp
index 32220f0..360dbb2 100644
--- a/core/fxcrt/cfx_timer_unittest.cpp
+++ b/core/fxcrt/cfx_timer_unittest.cpp
@@ -14,6 +14,8 @@
using testing::Return;
using testing::SaveArg;
+namespace {
+
class MockTimerScheduler : public CFX_Timer::HandlerIface {
public:
MOCK_METHOD2(SetTimer, int(int32_t uElapse, TimerCallback lpTimerFunc));
@@ -25,7 +27,14 @@
MOCK_METHOD0(OnTimerFired, void());
};
-TEST(CFX_Timer, ValidTimers) {
+} // namespace
+
+class CFXTimer : public testing::Test {
+ void SetUp() override { CFX_Timer::InitializeGlobals(); }
+ void TearDown() override { CFX_Timer::DestroyGlobals(); }
+};
+
+TEST_F(CFXTimer, ValidTimers) {
CFX_Timer::HandlerIface::TimerCallback fn1 = nullptr;
CFX_Timer::HandlerIface::TimerCallback fn2 = nullptr;
@@ -56,7 +65,7 @@
(*fn1)(1002);
}
-TEST(CFX_Timer, MisbehavingEmbedder) {
+TEST_F(CFXTimer, MisbehavingEmbedder) {
CFX_Timer::HandlerIface::TimerCallback fn1 = nullptr;
MockTimerScheduler scheduler;
diff --git a/fpdfsdk/fpdf_view.cpp b/fpdfsdk/fpdf_view.cpp
index d6a58cc..fbe75d9 100644
--- a/fpdfsdk/fpdf_view.cpp
+++ b/fpdfsdk/fpdf_view.cpp
@@ -31,6 +31,7 @@
#include "core/fpdfdoc/cpdf_nametree.h"
#include "core/fpdfdoc/cpdf_viewerpreferences.h"
#include "core/fxcrt/cfx_read_only_span_stream.h"
+#include "core/fxcrt/cfx_timer.h"
#include "core/fxcrt/fx_safe_types.h"
#include "core/fxcrt/fx_stream.h"
#include "core/fxcrt/fx_system.h"
@@ -229,6 +230,7 @@
return;
FX_InitializeMemoryAllocators();
+ CFX_Timer::InitializeGlobals();
CFX_GEModule::Create(config ? config->m_pUserFontPaths : nullptr);
CPDF_PageModule::Create();
@@ -261,6 +263,7 @@
CPDF_PageModule::Destroy();
CFX_GEModule::Destroy();
+ CFX_Timer::DestroyGlobals();
g_bLibraryInitialized = false;
}
diff --git a/fxjs/global_timer.cpp b/fxjs/global_timer.cpp
index 035aff8..e54e635 100644
--- a/fxjs/global_timer.cpp
+++ b/fxjs/global_timer.cpp
@@ -12,18 +12,26 @@
#include "fxjs/cjs_app.h"
#include "third_party/base/check.h"
#include "third_party/base/containers/contains.h"
-#include "third_party/base/no_destructor.h"
namespace {
using TimerMap = std::map<int32_t, GlobalTimer*>;
-TimerMap& GetGlobalTimerMap() {
- static pdfium::base::NoDestructor<TimerMap> timer_map;
- return *timer_map;
-}
+TimerMap* g_global_timer_map = nullptr;
} // namespace
+// static
+void GlobalTimer::InitializeGlobals() {
+ CHECK(!g_global_timer_map);
+ g_global_timer_map = new TimerMap();
+}
+
+// static
+void GlobalTimer::DestroyGlobals() {
+ delete g_global_timer_map;
+ g_global_timer_map = nullptr;
+}
+
GlobalTimer::GlobalTimer(CJS_App* pObj,
CJS_Runtime* pRuntime,
Type nType,
@@ -37,8 +45,8 @@
m_pRuntime(pRuntime),
m_pEmbedApp(pObj) {
if (HasValidID()) {
- DCHECK(!pdfium::Contains(GetGlobalTimerMap(), m_nTimerID));
- GetGlobalTimerMap()[m_nTimerID] = this;
+ DCHECK(!pdfium::Contains((*g_global_timer_map), m_nTimerID));
+ (*g_global_timer_map)[m_nTimerID] = this;
}
}
@@ -49,15 +57,16 @@
if (m_pRuntime && m_pRuntime->GetTimerHandler())
m_pRuntime->GetTimerHandler()->KillTimer(m_nTimerID);
- DCHECK(pdfium::Contains(GetGlobalTimerMap(), m_nTimerID));
- GetGlobalTimerMap().erase(m_nTimerID);
+ DCHECK(pdfium::Contains((*g_global_timer_map), m_nTimerID));
+ g_global_timer_map->erase(m_nTimerID);
}
// static
void GlobalTimer::Trigger(int32_t nTimerID) {
- auto it = GetGlobalTimerMap().find(nTimerID);
- if (it == GetGlobalTimerMap().end())
+ auto it = g_global_timer_map->find(nTimerID);
+ if (it == g_global_timer_map->end()) {
return;
+ }
GlobalTimer* pTimer = it->second;
if (pTimer->m_bProcessing)
@@ -68,9 +77,10 @@
pTimer->m_pEmbedApp->TimerProc(pTimer);
// Timer proc may have destroyed timer, find it again.
- it = GetGlobalTimerMap().find(nTimerID);
- if (it == GetGlobalTimerMap().end())
+ it = g_global_timer_map->find(nTimerID);
+ if (it == g_global_timer_map->end()) {
return;
+ }
pTimer = it->second;
pTimer->m_bProcessing = false;
@@ -80,9 +90,10 @@
// static
void GlobalTimer::Cancel(int32_t nTimerID) {
- auto it = GetGlobalTimerMap().find(nTimerID);
- if (it == GetGlobalTimerMap().end())
+ auto it = g_global_timer_map->find(nTimerID);
+ if (it == g_global_timer_map->end()) {
return;
+ }
GlobalTimer* pTimer = it->second;
pTimer->m_pEmbedApp->CancelProc(pTimer);
diff --git a/fxjs/global_timer.h b/fxjs/global_timer.h
index 106c9e6..53a67b7 100644
--- a/fxjs/global_timer.h
+++ b/fxjs/global_timer.h
@@ -19,6 +19,9 @@
kOneShot = true,
};
+ static void InitializeGlobals();
+ static void DestroyGlobals();
+
GlobalTimer(CJS_App* pObj,
CJS_Runtime* pRuntime,
Type nType,
diff --git a/fxjs/ijs_runtime.cpp b/fxjs/ijs_runtime.cpp
index 0308524..11c90fd 100644
--- a/fxjs/ijs_runtime.cpp
+++ b/fxjs/ijs_runtime.cpp
@@ -10,6 +10,7 @@
#include "fpdfsdk/cpdfsdk_formfillenvironment.h"
#include "fxjs/cfxjs_engine.h"
#include "fxjs/cjs_runtime.h"
+#include "fxjs/global_timer.h"
#ifdef PDF_ENABLE_XFA
#include "fxjs/gc/heap.h"
#endif // PDF_ENABLE_XFA
@@ -25,6 +26,7 @@
// static
void IJS_Runtime::Initialize(unsigned int slot, void* isolate, void* platform) {
#ifdef PDF_ENABLE_V8
+ GlobalTimer::InitializeGlobals();
FXJS_Initialize(slot, static_cast<v8::Isolate*>(isolate));
#ifdef PDF_ENABLE_XFA
FXGC_Initialize(static_cast<v8::Platform*>(platform),
@@ -40,6 +42,7 @@
FXGC_Release();
#endif // PDF_ENABLE_XFA
FXJS_Release();
+ GlobalTimer::DestroyGlobals();
#endif // PDF_ENABLE_V8
}