Skip to content

Commit 8364b62

Browse files
authored
fix: potential dangling pointer in api::Screen (electron#49536)
fixes a regression from electron#49506
1 parent 441729c commit 8364b62

File tree

2 files changed

+52
-27
lines changed

2 files changed

+52
-27
lines changed

shell/browser/api/electron_api_screen.cc

Lines changed: 44 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -70,16 +70,26 @@ void DelayEmitWithMetrics(Screen* screen,
7070
screen->Emit(name, display, metrics);
7171
}
7272

73+
// Calls the one-liner `display::Screen::Get()` to get ui's global screen.
74+
// NOTE: during shutdown, that screen can be destroyed before us. This means:
75+
// 1. Call this instead of keeping a possibly-dangling raw_ptr in api::Screen.
76+
// 2. Always check this function's return value for nullptr before use.
77+
[[nodiscard]] auto* GetDisplayScreen() {
78+
return display::Screen::Get();
79+
}
80+
81+
[[nodiscard]] auto GetFallbackDisplay() {
82+
return display::Display::GetDefaultDisplay();
83+
}
7384
} // namespace
7485

75-
Screen::Screen(display::Screen* screen) : screen_{screen} {
76-
screen_->AddObserver(this);
86+
Screen::Screen() {
87+
if (auto* screen = GetDisplayScreen())
88+
screen->AddObserver(this);
7789
}
7890

7991
Screen::~Screen() {
80-
// Use `display::Screen::Get()` here, not our cached `screen_`:
81-
// during shutdown, it can get torn down before us.
82-
if (auto* screen = display::Screen::Get())
92+
if (auto* screen = GetDisplayScreen())
8393
screen->RemoveObserver(this);
8494
}
8595

@@ -95,7 +105,33 @@ gfx::Point Screen::GetCursorScreenPoint(v8::Isolate* isolate) {
95105
return {};
96106
}
97107
#endif
98-
return screen_->GetCursorScreenPoint();
108+
auto* screen = GetDisplayScreen();
109+
return screen ? screen->GetCursorScreenPoint() : gfx::Point{};
110+
}
111+
112+
display::Display Screen::GetPrimaryDisplay() const {
113+
const auto* screen = GetDisplayScreen();
114+
return screen ? screen->GetPrimaryDisplay() : GetFallbackDisplay();
115+
}
116+
117+
std::vector<display::Display> Screen::GetAllDisplays() const {
118+
if (const auto* screen = GetDisplayScreen())
119+
return screen->GetAllDisplays();
120+
121+
// Even though this is only reached during shutdown by Screen::Get() failing,
122+
// display::Screen::GetAllDisplays() is guaranteed to return >= 1 display.
123+
// For consistency with that API, let's return a nonempty vector here.
124+
return {GetFallbackDisplay()};
125+
}
126+
127+
display::Display Screen::GetDisplayNearestPoint(const gfx::Point& point) const {
128+
const auto* screen = GetDisplayScreen();
129+
return screen ? screen->GetDisplayNearestPoint(point) : GetFallbackDisplay();
130+
}
131+
132+
display::Display Screen::GetDisplayMatching(const gfx::Rect& match_rect) const {
133+
const auto* screen = GetDisplayScreen();
134+
return screen ? screen->GetDisplayMatching(match_rect) : GetFallbackDisplay();
99135
}
100136

101137
#if BUILDFLAG(IS_WIN)
@@ -182,14 +218,14 @@ Screen* Screen::Create(gin_helper::ErrorThrower error_thrower) {
182218
return {};
183219
}
184220

185-
display::Screen* screen = display::Screen::Get();
221+
display::Screen* screen = GetDisplayScreen();
186222
if (!screen) {
187223
error_thrower.ThrowError("Failed to get screen information");
188224
return {};
189225
}
190226

191227
return cppgc::MakeGarbageCollected<Screen>(
192-
error_thrower.isolate()->GetCppHeap()->GetAllocationHandle(), screen);
228+
error_thrower.isolate()->GetCppHeap()->GetAllocationHandle());
193229
}
194230

195231
gin::ObjectTemplateBuilder Screen::GetObjectTemplateBuilder(
@@ -218,7 +254,6 @@ const gin::WrapperInfo* Screen::wrapper_info() const {
218254
const char* Screen::GetHumanReadableName() const {
219255
return "Electron / Screen";
220256
}
221-
222257
} // namespace electron::api
223258

224259
namespace {

shell/browser/api/electron_api_screen.h

Lines changed: 8 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
#include <vector>
99

10-
#include "base/memory/raw_ptr.h"
1110
#include "gin/wrappable.h"
1211
#include "shell/browser/event_emitter_mixin.h"
1312
#include "ui/display/display_observer.h"
@@ -43,22 +42,16 @@ class Screen final : public gin::Wrappable<Screen>,
4342
Screen& operator=(const Screen&) = delete;
4443

4544
// Make public for cppgc::MakeGarbageCollected.
46-
explicit Screen(display::Screen* screen);
45+
Screen();
4746
~Screen() override;
4847

49-
gfx::Point GetCursorScreenPoint(v8::Isolate* isolate);
50-
display::Display GetPrimaryDisplay() const {
51-
return screen_->GetPrimaryDisplay();
52-
}
53-
const std::vector<display::Display>& GetAllDisplays() const {
54-
return screen_->GetAllDisplays();
55-
}
56-
display::Display GetDisplayNearestPoint(const gfx::Point& point) const {
57-
return screen_->GetDisplayNearestPoint(point);
58-
}
59-
display::Display GetDisplayMatching(const gfx::Rect& match_rect) const {
60-
return screen_->GetDisplayMatching(match_rect);
61-
}
48+
[[nodiscard]] gfx::Point GetCursorScreenPoint(v8::Isolate* isolate);
49+
[[nodiscard]] display::Display GetPrimaryDisplay() const;
50+
[[nodiscard]] std::vector<display::Display> GetAllDisplays() const;
51+
[[nodiscard]] display::Display GetDisplayNearestPoint(
52+
const gfx::Point& point) const;
53+
[[nodiscard]] display::Display GetDisplayMatching(
54+
const gfx::Rect& match_rect) const;
6255

6356
gfx::PointF ScreenToDIPPoint(const gfx::PointF& point_px);
6457
gfx::Point DIPToScreenPoint(const gfx::Point& point_dip);
@@ -68,9 +61,6 @@ class Screen final : public gin::Wrappable<Screen>,
6861
void OnDisplaysRemoved(const display::Displays& removed_displays) override;
6962
void OnDisplayMetricsChanged(const display::Display& display,
7063
uint32_t changed_metrics) override;
71-
72-
private:
73-
raw_ptr<display::Screen> screen_;
7464
};
7565

7666
} // namespace electron::api

0 commit comments

Comments
 (0)