Repository: electron/electron
Pull request: fix: dangling raw_ptr<Session> in UserDataLink

#### Description of Change

Fix a dangling `raw_ptr<Session>` in Session's UserDataLink class. This class is for mapping BrowserContext to Session to implement `Session::FromBrowserContext()`. This approach converts those `raw_ptr` to `base::WeakPtr` to avoid the dangling raw_ptr.

The dangling raw ptr error:

```
[561781:0705/121435.715912:ERROR:partition_alloc_support.cc(687)] Detected dangling raw_ptr with id=0x0000026400bd9fd8:
[DanglingSignature]	gin_helper::CleanedUpAtExit::DoCleanup() [../../electron/shell/common/gin_helper/cleaned_up_at_exit.cc:30:5]	No active task	electron::api::(anonymous namespace)::UserDataLink::~UserDataLink() [../../base/allocator/partition_allocator/src/partition_alloc/pointers/raw_ptr_backup_ref_impl.h:200:7]	No active task

The memory was freed at:
#0 0x5f8f01799502 base::debug::CollectStackTrace() [../../base/debug/stack_trace_posix.cc:1044:7]
#1 0x5f8f0178125c base::debug::StackTrace::StackTrace() [../../base/debug/stack_trace.cc:242:20]
#2 0x5f8f0179faba base::allocator::(anonymous namespace)::DanglingRawPtrDetected() [../../base/allocator/partition_alloc_support.cc:497:11]
#3 0x5f8f0184dfb2 allocator_shim::internal::PartitionFree() [../../base/allocator/partition_allocator/src/partition_alloc/in_slot_metadata.h:396:5]
#4 0x5f8efbabf712 gin_helper::CleanedUpAtExit::DoCleanup() [../../electron/shell/common/gin_helper/cleaned_up_at_exit.cc:30:5]
#5 0x5f8efba0a182 electron::JavascriptEnvironment::DestroyMicrotasksRunner() [../../electron/shell/browser/javascript_environment.cc:183:5]
#6 0x5f8efb9e8f29 electron::ElectronBrowserMainParts::PostMainMessageLoopRun() [../../electron/shell/browser/electron_browser_main_parts.cc:605:12]
#7 0x5f8effe69fdd content::BrowserMainLoop::ShutdownThreadsAndCleanUp() [../../content/browser/browser_main_loop.cc:1148:13]
#8 0x5f8effe6c40b content::BrowserMainRunnerImpl::Shutdown() [../../content/browser/browser_main_runner_impl.cc:194:17]
#9 0x5f8effe65d77 content::BrowserMain() [../../content/browser/browser_main.cc:43:16]
#10 0x5f8efbcf16a8 content::RunBrowserProcessMain() [../../content/app/content_main_runner_impl.cc:739:10]
#11 0x5f8efbcf46a2 content::ContentMainRunnerImpl::RunBrowser() [../../content/app/content_main_runner_impl.cc:1325:10]
#12 0x5f8efbcf3c83 content::ContentMainRunnerImpl::Run() [../../content/app/content_main_runner_impl.cc:1177:12]
#13 0x5f8efbcefe7b content::RunContentProcess() [../../content/app/content_main.cc:330:36]
#14 0x5f8efbcf01a0 content::ContentMain() [../../content/app/content_main.cc:343:10]
#15 0x5f8efb8a8639 main [../../electron/shell/app/electron_main_linux.cc:45:10]
#16 0x7f138942a1ca (/usr/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9)
#17 0x7f138942a28b __libc_start_main
#18 0x5f8efb88e02a _start

Task trace:
No active task.
The dangling raw_ptr was released at:
#0 0x5f8f01799502 base::debug::CollectStackTrace() [../../base/debug/stack_trace_posix.cc:1044:7]
#1 0x5f8f0178125c base::debug::StackTrace::StackTrace() [../../base/debug/stack_trace.cc:242:20]
#2 0x5f8f0179fbab base::allocator::(anonymous namespace)::DanglingRawPtrReleased<>() [../../base/allocator/partition_alloc_support.cc:659:21]
#3 0x5f8f017e5265 base::internal::RawPtrBackupRefImpl<>::ReleaseInternal() [../../base/allocator/partition_allocator/src/partition_alloc/in_slot_metadata.h:224:7]
#4 0x5f8efb94717f electron::api::(anonymous namespace)::UserDataLink::~UserDataLink() [../../base/allocator/partition_allocator/src/partition_alloc/pointers/raw_ptr_backup_ref_impl.h:200:7]
#5 0x5f8f016ecfd4 base::SupportsUserData::~SupportsUserData() [../../third_party/libc++/src/include/__memory/unique_ptr.h:67:5]
#6 0x5f8effe44f74 content::BrowserContext::~BrowserContext() [../../content/browser/browser_context.cc:97:1]
#7 0x5f8efb9e0d4c electron::ElectronBrowserContext::~ElectronBrowserContext() [../../electron/shell/browser/electron_browser_context.cc:384:1]
#8 0x5f8efb9e0e0e electron::ElectronBrowserContext::~ElectronBrowserContext() [../../electron/shell/browser/electron_browser_context.cc:372:51]
#9 0x5f8efb9e903b electron::ElectronBrowserMainParts::PostMainMessageLoopRun() [../../third_party/libc++/src/include/__memory/unique_ptr.h:67:5]
#10 0x5f8effe69fdd content::BrowserMainLoop::ShutdownThreadsAndCleanUp() [../../content/browser/browser_main_loop.cc:1148:13]
#11 0x5f8effe6c40b content::BrowserMainRunnerImpl::Shutdown() [../../content/browser/browser_main_runner_impl.cc:194:17]
#12 0x5f8effe65d77 content::BrowserMain() [../../content/browser/browser_main.cc:43:16]
#13 0x5f8efbcf16a8 content::RunBrowserProcessMain() [../../content/app/content_main_runner_impl.cc:739:10]
#14 0x5f8efbcf46a2 content::ContentMainRunnerImpl::RunBrowser() [../../content/app/content_main_runner_impl.cc:1325:10]
#15 0x5f8efbcf3c83 content::ContentMainRunnerImpl::Run() [../../content/app/content_main_runner_impl.cc:1177:12]
#16 0x5f8efbcefe7b content::RunContentProcess() [../../content/app/content_main.cc:330:36]
#17 0x5f8efbcf01a0 content::ContentMain() [../../content/app/content_main.cc:343:10]
#18 0x5f8efb8a8639 main [../../electron/shell/app/electron_main_linux.cc:45:10]
#19 0x7f138942a1ca (/usr/lib/x86_64-linux-gnu/libc.so.6+0x2a1c9)
#20 0x7f138942a28b __libc_start_main
#21 0x5f8efb88e02a _start
```

#### Checklist

- [x] PR description included and stakeholders cc'd
- [x] `npm test` passes
- [x] [PR release notes](https://github.com/electron/clerk/blob/main/README.md) describe the change in a way relevant to app developers, and are [capitalized, punctuated, and past tense](https://github.com/electron/clerk/blob/main/README.md#examples).

#### Release Notes

Notes: none

Changed files:
filename: shell/browser/api/electron_api_session.cc
patch: @@ -530,9 +530,10 @@ class DictionaryObserver final : public SpellcheckCustomDictionary::Observer {
 #endif  // BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
 
 struct UserDataLink : base::SupportsUserData::Data {
-  explicit UserDataLink(Session* ses) : session(ses) {}
+  explicit UserDataLink(base::WeakPtr<Session> session_in)
+      : session{std::move(session_in)} {}
 
-  raw_ptr<Session> session;
+  base::WeakPtr<Session> session;
 };
 
 const void* kElectronApiSessionKey = &kElectronApiSessionKey;
@@ -553,8 +554,9 @@ Session::Session(v8::Isolate* isolate, ElectronBrowserContext* browser_context)
 
   protocol_.Reset(isolate, Protocol::Create(isolate, browser_context).ToV8());
 
-  browser_context->SetUserData(kElectronApiSessionKey,
-                               std::make_unique<UserDataLink>(this));
+  browser_context->SetUserData(
+      kElectronApiSessionKey,
+      std::make_unique<UserDataLink>(weak_factory_.GetWeakPtr()));
 
 #if BUILDFLAG(ENABLE_BUILTIN_SPELLCHECKER)
   if (auto* service =
@@ -1511,7 +1513,7 @@ bool Session::IsSpellCheckerEnabled() const {
 Session* Session::FromBrowserContext(content::BrowserContext* context) {
   auto* data =
       static_cast<UserDataLink*>(context->GetUserData(kElectronApiSessionKey));
-  return data ? data->session : nullptr;
+  return data ? data->session.get() : nullptr;
 }
 
 // static

filename: shell/browser/api/electron_api_session.h
patch: @@ -10,6 +10,7 @@
 #include <vector>
 
 #include "base/memory/raw_ptr.h"
+#include "base/memory/weak_ptr.h"
 #include "base/values.h"
 #include "content/public/browser/download_manager.h"
 #include "electron/buildflags/buildflags.h"
@@ -218,6 +219,8 @@ class Session : public gin::Wrappable<Session>,
   base::UnguessableToken network_emulation_token_;
 
   const raw_ref<ElectronBrowserContext> browser_context_;
+
+  base::WeakPtrFactory<Session> weak_factory_{this};
 };
 
 }  // namespace api