fix: use render client id to track deleted render process hosts (#14520)

* fix: use render client id to track deleted render process hosts

Instead of relying on OS process id, which may not be unique
when a process is reused, we rely on the renderer client id
passed by the content layer when starting the renderer process
which is guaranteed to be unique for the lifetime of the app.

* fix: store context id as int64_t

Ensuring that it doesn't wrap easily with a large number
of context creation on some malformed web pages.
This commit is contained in:
Robo 2018-09-11 23:48:10 +05:30 committed by Shelley Vohr
parent 2157d09956
commit 14ed71fa1b
5 changed files with 27 additions and 31 deletions

View file

@ -56,7 +56,6 @@
#include "atom/common/native_mate_converters/value_converter.h" #include "atom/common/native_mate_converters/value_converter.h"
#include "atom/common/options_switches.h" #include "atom/common/options_switches.h"
#include "base/message_loop/message_loop.h" #include "base/message_loop/message_loop.h"
#include "base/process/process_handle.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "base/threading/thread_task_runner_handle.h" #include "base/threading/thread_task_runner_handle.h"
#include "base/values.h" #include "base/values.h"
@ -777,8 +776,7 @@ void WebContents::RenderViewCreated(content::RenderViewHost* render_view_host) {
} }
void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) { void WebContents::RenderViewDeleted(content::RenderViewHost* render_view_host) {
Emit("render-view-deleted", render_view_host->GetProcess()->GetID(), Emit("render-view-deleted", render_view_host->GetProcess()->GetID());
base::GetProcId(render_view_host->GetProcess()->GetHandle()));
} }
void WebContents::RenderProcessGone(base::TerminationStatus status) { void WebContents::RenderProcessGone(base::TerminationStatus status) {

View file

@ -16,13 +16,13 @@
#include "atom/renderer/content_settings_observer.h" #include "atom/renderer/content_settings_observer.h"
#include "atom/renderer/preferences_manager.h" #include "atom/renderer/preferences_manager.h"
#include "base/command_line.h" #include "base/command_line.h"
#include "base/process/process.h"
#include "base/strings/string_split.h" #include "base/strings/string_split.h"
#include "base/strings/stringprintf.h" #include "base/strings/stringprintf.h"
#include "chrome/renderer/media/chrome_key_systems.h" #include "chrome/renderer/media/chrome_key_systems.h"
#include "chrome/renderer/printing/print_web_view_helper.h" #include "chrome/renderer/printing/print_web_view_helper.h"
#include "chrome/renderer/tts_dispatcher.h" #include "chrome/renderer/tts_dispatcher.h"
#include "content/public/common/content_constants.h" #include "content/public/common/content_constants.h"
#include "content/public/common/content_switches.h"
#include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_frame.h"
#include "content/public/renderer/render_view.h" #include "content/public/renderer/render_view.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
@ -50,14 +50,6 @@
#include "chrome/renderer/pepper/pepper_helper.h" #include "chrome/renderer/pepper/pepper_helper.h"
#endif // defined(ENABLE_PEPPER_FLASH) #endif // defined(ENABLE_PEPPER_FLASH)
// This is defined in later versions of Chromium, remove this if you see
// compiler complaining duplicate defines.
#if defined(OS_WIN) || defined(OS_FUCHSIA)
#define CrPRIdPid "ld"
#else
#define CrPRIdPid "d"
#endif
namespace atom { namespace atom {
namespace { namespace {
@ -71,8 +63,8 @@ v8::Local<v8::Value> GetRenderProcessPreferences(
return v8::Null(isolate); return v8::Null(isolate);
} }
std::vector<std::string> ParseSchemesCLISwitch(const char* switch_name) { std::vector<std::string> ParseSchemesCLISwitch(base::CommandLine* command_line,
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); const char* switch_name) {
std::string custom_schemes = command_line->GetSwitchValueASCII(switch_name); std::string custom_schemes = command_line->GetSwitchValueASCII(switch_name);
return base::SplitString(custom_schemes, ",", base::TRIM_WHITESPACE, return base::SplitString(custom_schemes, ",", base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY); base::SPLIT_WANT_NONEMPTY);
@ -81,13 +73,21 @@ std::vector<std::string> ParseSchemesCLISwitch(const char* switch_name) {
} // namespace } // namespace
RendererClientBase::RendererClientBase() { RendererClientBase::RendererClientBase() {
auto* command_line = base::CommandLine::ForCurrentProcess();
// Parse --standard-schemes=scheme1,scheme2 // Parse --standard-schemes=scheme1,scheme2
std::vector<std::string> standard_schemes_list = std::vector<std::string> standard_schemes_list =
ParseSchemesCLISwitch(switches::kStandardSchemes); ParseSchemesCLISwitch(command_line, switches::kStandardSchemes);
for (const std::string& scheme : standard_schemes_list) for (const std::string& scheme : standard_schemes_list)
url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITHOUT_PORT); url::AddStandardScheme(scheme.c_str(), url::SCHEME_WITHOUT_PORT);
isolated_world_ = base::CommandLine::ForCurrentProcess()->HasSwitch( isolated_world_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
switches::kContextIsolation); switches::kContextIsolation);
// We rely on the unique process host id which is notified to the
// renderer process via command line switch from the content layer,
// if this switch is removed from the content layer for some reason,
// we should define our own.
DCHECK(command_line->HasSwitch(::switches::kRendererClientId));
renderer_client_id_ =
command_line->GetSwitchValueASCII(::switches::kRendererClientId);
} }
RendererClientBase::~RendererClientBase() {} RendererClientBase::~RendererClientBase() {}
@ -95,10 +95,9 @@ RendererClientBase::~RendererClientBase() {}
void RendererClientBase::DidCreateScriptContext( void RendererClientBase::DidCreateScriptContext(
v8::Handle<v8::Context> context, v8::Handle<v8::Context> context,
content::RenderFrame* render_frame) { content::RenderFrame* render_frame) {
// global.setHidden("contextId", `${processId}-${++next_context_id_}`) // global.setHidden("contextId", `${processHostId}-${++next_context_id_}`)
std::string context_id = base::StringPrintf( auto context_id = base::StringPrintf(
"%" CrPRIdPid "-%d", base::GetProcId(base::Process::Current().Handle()), "%s-%" PRId64, renderer_client_id_.c_str(), ++next_context_id_);
++next_context_id_);
v8::Isolate* isolate = context->GetIsolate(); v8::Isolate* isolate = context->GetIsolate();
v8::Local<v8::String> key = mate::StringToSymbol(isolate, "contextId"); v8::Local<v8::String> key = mate::StringToSymbol(isolate, "contextId");
v8::Local<v8::Private> private_key = v8::Private::ForApi(isolate, key); v8::Local<v8::Private> private_key = v8::Private::ForApi(isolate, key);
@ -116,6 +115,8 @@ void RendererClientBase::AddRenderBindings(
} }
void RendererClientBase::RenderThreadStarted() { void RendererClientBase::RenderThreadStarted() {
auto* command_line = base::CommandLine::ForCurrentProcess();
blink::WebCustomElement::AddEmbedderCustomElementName("webview"); blink::WebCustomElement::AddEmbedderCustomElementName("webview");
blink::WebCustomElement::AddEmbedderCustomElementName("browserplugin"); blink::WebCustomElement::AddEmbedderCustomElementName("browserplugin");
@ -137,7 +138,7 @@ void RendererClientBase::RenderThreadStarted() {
// Parse --secure-schemes=scheme1,scheme2 // Parse --secure-schemes=scheme1,scheme2
std::vector<std::string> secure_schemes_list = std::vector<std::string> secure_schemes_list =
ParseSchemesCLISwitch(switches::kSecureSchemes); ParseSchemesCLISwitch(command_line, switches::kSecureSchemes);
for (const std::string& scheme : secure_schemes_list) for (const std::string& scheme : secure_schemes_list)
blink::SchemeRegistry::RegisterURLSchemeAsSecure( blink::SchemeRegistry::RegisterURLSchemeAsSecure(
WTF::String::FromUTF8(scheme.data(), scheme.length())); WTF::String::FromUTF8(scheme.data(), scheme.length()));
@ -151,7 +152,6 @@ void RendererClientBase::RenderThreadStarted() {
#if defined(OS_WIN) #if defined(OS_WIN)
// Set ApplicationUserModelID in renderer process. // Set ApplicationUserModelID in renderer process.
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
base::string16 app_id = base::string16 app_id =
command_line->GetSwitchValueNative(switches::kAppUserModelId); command_line->GetSwitchValueNative(switches::kAppUserModelId);
if (!app_id.empty()) { if (!app_id.empty()) {

View file

@ -56,9 +56,9 @@ class RendererClientBase : public content::ContentRendererClient {
std::unique_ptr<PreferencesManager> preferences_manager_; std::unique_ptr<PreferencesManager> preferences_manager_;
ChromeKeySystemsProvider key_systems_provider_; ChromeKeySystemsProvider key_systems_provider_;
bool isolated_world_; bool isolated_world_;
std::string renderer_client_id_;
// An increasing ID used for indentifying an V8 context in this process. // An increasing ID used for indentifying an V8 context in this process.
int next_context_id_ = 0; int64_t next_context_id_ = 0;
}; };
} // namespace atom } // namespace atom

View file

@ -87,9 +87,6 @@ class ObjectsRegistry {
// Private: Dereference the object from store. // Private: Dereference the object from store.
dereference (id) { dereference (id) {
// FIXME(MarshallOfSound): We should remove this once remote deref works well
if (process.env.ELECTRON_DISABLE_REMOTE_DEREFERENCING) return
let pointer = this.storage[id] let pointer = this.storage[id]
if (pointer == null) { if (pointer == null) {
return return
@ -103,10 +100,11 @@ class ObjectsRegistry {
// Private: Clear the storage when renderer process is destroyed. // Private: Clear the storage when renderer process is destroyed.
registerDeleteListener (webContents, contextId) { registerDeleteListener (webContents, contextId) {
// contextId => ${OSProcessId}-${contextCount} // contextId => ${processHostId}-${contextCount}
const OSProcessId = contextId.split('-')[0] const processHostId = contextId.split('-')[0]
const listener = (event, deletedProcessId, deletedOSProcessId) => { const listener = (event, deletedProcessHostId) => {
if (deletedOSProcessId && deletedOSProcessId.toString() === OSProcessId) { if (deletedProcessHostId &&
deletedProcessHostId.toString() === processHostId) {
webContents.removeListener('render-view-deleted', listener) webContents.removeListener('render-view-deleted', listener)
this.clear(webContents, contextId) this.clear(webContents, contextId)
} }

View file

@ -17,7 +17,7 @@
} }
// This should trigger a dereference and a remote getURL call should fail // This should trigger a dereference and a remote getURL call should fail
contents.emit('render-view-deleted', {}, '', contents.getOSProcessId()) contents.emit('render-view-deleted', {}, contents.getProcessId())
try { try {
contents.getURL() contents.getURL()
ipcRenderer.send('error-message', 'No error thrown') ipcRenderer.send('error-message', 'No error thrown')