From adcac2c37c9a004aa7f698b219a62c8980ddee90 Mon Sep 17 00:00:00 2001 From: Marshall Greenblatt Date: Thu, 8 May 2025 18:33:07 -0400 Subject: [PATCH] win: Add bootstrap[c].exe for sandbox integration (see #3824) Replace cef_sandbox.lib usage with bootstrap executables. See the SandboxSetup Wiki page for details. --- BUILD.gn | 215 ++++++++++++++++++ include/cef_sandbox_win.h | 70 +++++- include/internal/cef_app_win.h | 2 + .../chrome_content_browser_client_cef.cc | 15 ++ libcef/browser/context.cc | 123 +--------- libcef/browser/preferred_stack_size_win.inc | 129 +++++++++++ libcef_dll/bootstrap/bootstrap_util_win.cc | 82 +++++++ libcef_dll/bootstrap/bootstrap_util_win.h | 51 +++++ libcef_dll/bootstrap/bootstrap_win.cc | 179 +++++++++++++++ libcef_dll/bootstrap/win/bootstrap.ico | Bin 0 -> 23558 bytes libcef_dll/bootstrap/win/bootstrap.rc | 133 +++++++++++ libcef_dll/bootstrap/win/resource.h | 26 +++ tests/cefclient/browser/osr_window_win.cc | 2 +- tests/cefclient/browser/root_window_win.cc | 4 +- tests/cefclient/browser/temp_window_win.cc | 3 +- tests/cefclient/cefclient_win.cc | 54 ++--- tests/cefsimple/cefsimple_win.cc | 107 +++++---- tests/ceftests/os_rendering_unittest.cc | 4 +- tests/ceftests/run_all_unittests.cc | 94 ++++---- .../main_message_loop_external_pump_win.cc | 2 +- tests/shared/browser/resource_util_win.cc | 3 +- tests/shared/browser/util_win.cc | 11 +- tests/shared/browser/util_win.h | 4 + tools/automate/automate-git.py | 64 ++---- tools/gclient_hook.py | 6 - tools/gn_args.py | 14 +- tools/make_distrib.py | 93 +++----- tools/msvs_env.bat | 73 ------ 28 files changed, 1116 insertions(+), 447 deletions(-) create mode 100644 libcef/browser/preferred_stack_size_win.inc create mode 100644 libcef_dll/bootstrap/bootstrap_util_win.cc create mode 100644 libcef_dll/bootstrap/bootstrap_util_win.h create mode 100644 libcef_dll/bootstrap/bootstrap_win.cc create mode 100644 libcef_dll/bootstrap/win/bootstrap.ico create mode 100644 libcef_dll/bootstrap/win/bootstrap.rc create mode 100644 libcef_dll/bootstrap/win/resource.h delete mode 100644 tools/msvs_env.bat diff --git a/BUILD.gn b/BUILD.gn index b3a64badc..ebf2bad48 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -319,6 +319,16 @@ group("cef") { ":libcef_static_unittests", ] + if (is_win) { + deps += [ + ":bootstrap", + ":bootstrapc", + ":cefclient_dll", + ":cefsimple_dll", + ":ceftests_dll", + ] + } + if (!is_linux || ozone_platform_x11) { deps += [ ":cefclient" ] } @@ -992,6 +1002,9 @@ source_set("libcef_static") { "libcef/browser/native/browser_platform_delegate_native_win.h", "libcef/browser/osr/browser_platform_delegate_osr_win.cc", "libcef/browser/osr/browser_platform_delegate_osr_win.h", + "libcef/browser/preferred_stack_size_win.inc", + "libcef_dll/bootstrap/bootstrap_util_win.cc", + "libcef_dll/bootstrap/bootstrap_util_win.h", ] deps += [ @@ -1228,6 +1241,73 @@ if (is_mac) { } } +# +# bootstrap target. +# + +if (is_win) { + bootstrap_sources = includes_common + + includes_win + [ + "libcef_dll/bootstrap/bootstrap_util_win.cc", + "libcef_dll/bootstrap/bootstrap_util_win.h", + "libcef_dll/bootstrap/bootstrap_win.cc", + "libcef_dll/bootstrap/win/bootstrap.rc", + "libcef_dll/bootstrap/win/resource.h", + "libcef/browser/preferred_stack_size_win.inc", + ] + + bootstrap_deps = [ + ":cef_sandbox", + ":make_version_header", + "//base", + "//build/win:default_exe_manifest", + ] + + # Windows application that initializes the sandbox and then passes + # execution to a client-provided DLL. + executable("bootstrap") { + # Necessary because the libcef target is testonly. + testonly = true + + sources = bootstrap_sources + deps = bootstrap_deps + + configs += [ ":libcef_includes_config" ] + + # Set /SUBSYSTEM:WINDOWS. + configs -= [ "//build/config/win:console" ] + configs += [ "//build/config/win:windowed" ] + + # Delay-load as many DLLs as possible for sandbox and startup perf + # improvements. + configs += [ "//build/config/win:delayloads" ] + + defines = [ + "CEF_BUILD_BOOTSTRAP", + ] + } + + # Like "bootstrap", but as a console application. + executable("bootstrapc") { + # Necessary because the libcef target is testonly. + testonly = true + + sources = bootstrap_sources + deps = bootstrap_deps + + configs += [ ":libcef_includes_config" ] + + # Delay-load as many DLLs as possible for sandbox and startup perf + # improvements. + configs += [ "//build/config/win:delayloads" ] + + defines = [ + "CEF_BUILD_BOOTSTRAP", + "CEF_BUILD_BOOTSTRAP_CONSOLE", + ] + } +} + # # Resource grit/pack targets. # @@ -2224,6 +2304,66 @@ if (is_mac) { } } + if (is_win) { + # Like the "cefclient" executable target, but building a DLL to be loaded by + # bootstrap.exe. + shared_library("cefclient_dll") { + # Necessary because the libcef target is testonly. + testonly = true + + output_name = "cefclient" + + sources = includes_common + + includes_win + + gypi_paths2.includes_wrapper + + gypi_paths2.shared_sources_browser + + gypi_paths2.shared_sources_common + + gypi_paths2.shared_sources_renderer + + gypi_paths2.shared_sources_win + + gypi_paths2.cefclient_sources_browser + + gypi_paths2.cefclient_sources_common + + gypi_paths2.cefclient_sources_renderer + + gypi_paths2.cefclient_sources_win + + gypi_paths2.cefclient_sources_resources_win_rc + + deps = [ + ":bootstrap", + ":libcef", + ":libcef_dll_wrapper", + ] + + defines = [ + "CEF_USE_ATL", + "CEF_USE_BOOTSTRAP", + ] + + # Delay-load as many DLLs as possible for sandbox and startup perf + # improvements. + configs += [ "//build/config/win:delayloads" ] + + libs = [ + "comctl32.lib", + "d3d11.lib", + "imm32.lib", + "oleacc.lib", + "rpcrt4.lib", + "shlwapi.lib", + ] + + if (target_cpu != "arm64") { + libs += [ + "glu32.lib", + "opengl32.lib", + ] + ldflags = [ + "/DELAYLOAD:glu32.dll", + "/DELAYLOAD:oleaut32.dll", + "/DELAYLOAD:opengl32.dll", + ] + } + } + } + # # cefsimple targets. @@ -2288,6 +2428,44 @@ if (is_mac) { } } + if (is_win) { + # Like the "cefsimple" executable target, but building a DLL to be loaded by + # bootstrap.exe. + shared_library("cefsimple_dll") { + # Necessary because the libcef target is testonly. + testonly = true + + output_name = "cefsimple" + + sources = includes_common + + includes_win + + gypi_paths2.includes_wrapper + + gypi_paths2.cefsimple_sources_common + + gypi_paths2.cefsimple_sources_win + + gypi_paths2.cefsimple_sources_resources_win_rc + + deps = [ + ":bootstrap", + ":libcef", + ":libcef_dll_wrapper", + ] + + defines = [ + "CEF_USE_BOOTSTRAP", + ] + + # Delay-load as many DLLs as possible for sandbox and startup perf + # improvements. + configs += [ "//build/config/win:delayloads" ] + + libs = [ + "comctl32.lib", + "shlwapi.lib", + "rpcrt4.lib", + ] + } + } + # # ceftests targets. @@ -2361,4 +2539,41 @@ if (is_mac) { configs += [ "//build/config/gcc:rpath_for_built_shared_libraries" ] } } + + if (is_win) { + # Like the "ceftests" executable target, but building a DLL to be loaded by + # bootstrapc.exe. + shared_library("ceftests_dll") { + testonly = true + + output_name = "ceftests" + + sources = includes_common + + gypi_paths2.includes_wrapper + + gypi_paths2.shared_sources_browser + + gypi_paths2.shared_sources_common + + gypi_paths2.shared_sources_renderer + + gypi_paths2.shared_sources_win + + gypi_paths2.ceftests_sources_common + + gypi_paths2.ceftests_sources_win + + gypi_paths2.ceftests_sources_resources_win_rc + + deps = [ + ":bootstrapc", + ":libcef", + ":libcef_dll_wrapper", + ":gtest_teamcity", + "//testing/gtest", + ] + + defines = [ + "CEF_USE_BOOTSTRAP", + "CEF_TESTS_IN_SRC_DIRECTORY", + ] + + # Delay-load as many DLLs as possible for sandbox and startup perf + # improvements. + configs += [ "//build/config/win:delayloads" ] + } + } } diff --git a/include/cef_sandbox_win.h b/include/cef_sandbox_win.h index bcef1fb3d..4b48ead40 100644 --- a/include/cef_sandbox_win.h +++ b/include/cef_sandbox_win.h @@ -37,6 +37,10 @@ #if defined(OS_WIN) +#if !defined(GENERATING_CEF_API_HASH) +#include +#endif + #ifdef __cplusplus extern "C" { #endif @@ -49,13 +53,34 @@ extern "C" { /// http://www.chromium.org/developers/design-documents/sandbox for complete /// details. /// -/// To enable the sandbox on Windows the following requirements must be met: -/// 1. Use the same executable for the browser process and all sub-processes. -/// 2. Link the executable with the cef_sandbox static library. -/// 3. Call the cef_sandbox_info_create() function from within the executable -/// (not from a separate DLL) and pass the resulting pointer into both the -/// CefExecuteProcess() and CefInitialize() functions via the -/// |windows_sandbox_info| parameter. +/// To enable the sandbox on Windows the same executable must be used for all +/// processes (browser process and sub-processes). This executable must link the +/// cef_sandbox static library and initialize the sandbox by calling +/// cef_sandbox_info_create. The resulting |sandbox_info| value must then be +/// passed to CefExecuteProcess and CefInitialize. +/// +/// Beginning with M138 the cef_sandbox static library can only be linked with +/// applications built as part of the CEF/Chromium build. This is due to +/// unavoidable dependencies on Chromium's bundled Clang/LLVM/libc++ toolchain. +/// Client applications therefore have 3 options for sandbox integration: +/// +/// 1. Build the client application (or a custom bootstrap executable) as part +/// of the CEF/Chromium build using Chromium's bundled Clang/LLVM/libc++ +/// toolchain. For details of this option see +/// https://bitbucket.org/chromiumembedded/cef/wiki/SandboxSetup.md +/// 2. Build the client application as a DLL using any toolchain and run using +/// the provided bootstrap.exe or bootstrapc.exe. The DLL implements +/// RunWinMain or RunConsoleMain respectively and gets passed the +/// |sandbox_info| parameter which it then forwards to CefExecuteProcess +/// and CefInitialize. The provided bootstrap executables can optionally be +/// renamed or modified [1] to meet client branding needs. +/// 3. Build the client application as an executable using any toolchain with +/// the sandbox disabled. Pass nullptr as the |sandbox_info| parameter to +/// CefExecuteProcess and CefInitialize. +/// +/// [1] Embedded executable resources such as icons and file properties can be +/// modified using Visual Studio or Resource Hacker tools. Be sure to code +/// sign all binaries after modification and before distribution to users. /// /// @@ -88,6 +113,37 @@ class CefScopedSandboxInfo { }; #endif // __cplusplus +#if defined(CEF_BUILD_BOOTSTRAP) +#define CEF_BOOTSTRAP_EXPORT __declspec(dllimport) +#else +#define CEF_BOOTSTRAP_EXPORT __declspec(dllexport) +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/// +/// Entry point to be implemented by client DLLs using bootstrap.exe for +/// windows (/SUBSYSTEM:WINDOWS) applications. +/// +CEF_BOOTSTRAP_EXPORT int RunWinMain(HINSTANCE hInstance, + LPTSTR lpCmdLine, + int nCmdShow, + void* sandbox_info); + +/// +/// Entry point to be implemented by client DLLs using bootstrapc.exe for +/// console (/SUBSYSTEM:CONSOLE) applications. +/// +CEF_BOOTSTRAP_EXPORT int RunConsoleMain(int argc, + char* argv[], + void* sandbox_info); + +#ifdef __cplusplus +} +#endif + #endif // defined(OS_WIN) #endif // CEF_INCLUDE_CEF_SANDBOX_WIN_H_ diff --git a/include/internal/cef_app_win.h b/include/internal/cef_app_win.h index 6bc968156..25ee27dce 100644 --- a/include/internal/cef_app_win.h +++ b/include/internal/cef_app_win.h @@ -41,6 +41,8 @@ #include #endif +#include "include/internal/cef_export.h" + #ifdef __cplusplus extern "C" { #endif diff --git a/libcef/browser/chrome/chrome_content_browser_client_cef.cc b/libcef/browser/chrome/chrome_content_browser_client_cef.cc index 8860355fd..6a947e69e 100644 --- a/libcef/browser/chrome/chrome_content_browser_client_cef.cc +++ b/libcef/browser/chrome/chrome_content_browser_client_cef.cc @@ -50,6 +50,10 @@ #include "cef/libcef/browser/chrome/chrome_web_contents_view_delegate_cef.h" #endif +#if BUILDFLAG(IS_WIN) +#include "cef/libcef_dll/bootstrap/bootstrap_util_win.h" +#endif + namespace { class CefSelectClientCertificateCallbackImpl @@ -214,6 +218,17 @@ void ChromeContentBrowserClientCef::AppendExtraCommandLineSwitches( command_line->CopySwitchesFrom(*browser_cmd, kSwitchNames); } +#if BUILDFLAG(IS_WIN) + { + const auto& module_value = bootstrap_util::GetValidatedModuleValue( + *browser_cmd, bootstrap_util::GetExePath()); + if (!module_value.empty()) { + command_line->AppendSwitchNative(bootstrap_util::switches::kModule, + module_value); + } + } +#endif + const std::string& process_type = command_line->GetSwitchValueASCII(switches::kProcessType); diff --git a/libcef/browser/context.cc b/libcef/browser/context.cc index 310c5e085..d9c49da36 100644 --- a/libcef/browser/context.cc +++ b/libcef/browser/context.cc @@ -22,9 +22,9 @@ #include "ui/base/ui_base_switches.h" #if BUILDFLAG(IS_WIN) -#include "base/debug/alias.h" #include "base/strings/utf_string_conversions.h" #include "cef/include/internal/cef_win.h" +#include "cef/libcef/browser/preferred_stack_size_win.inc" #include "chrome/chrome_elf/chrome_elf_main.h" #include "chrome/install_static/initialize_from_primary_module.h" #endif @@ -185,110 +185,6 @@ base::FilePath NormalizeCachePathAndSet(cef_string_t& path_str, return path; } -// Based on chrome/app/chrome_exe_main_win.cc. -// In 32-bit builds, the main thread starts with the default (small) stack size. -// The ARCH_CPU_32_BITS blocks here and below are in support of moving the main -// thread to a fiber with a larger stack size. -#if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_32_BITS) -// The information needed to transfer control to the large-stack fiber and later -// pass the main routine's exit code back to the small-stack fiber prior to -// termination. -struct FiberState { - FiberState(wWinMainPtr wWinMain, - HINSTANCE hInstance, - LPWSTR lpCmdLine, - int nCmdShow) { - this->wWinMain = wWinMain; - this->hInstance = hInstance; - this->lpCmdLine = lpCmdLine; - this->nCmdShow = nCmdShow; - } - - FiberState(mainPtr main, int argc, char** argv) { - this->main = main; - this->argc = argc; - this->argv = argv; - } - - wWinMainPtr wWinMain = nullptr; - HINSTANCE hInstance; - LPWSTR lpCmdLine; - int nCmdShow; - - mainPtr main = nullptr; - int argc; - char** argv; - - LPVOID original_fiber; - int fiber_result; -}; - -// A PFIBER_START_ROUTINE function run on a large-stack fiber that calls the -// main routine, stores its return value, and returns control to the small-stack -// fiber. |params| must be a pointer to a FiberState struct. -void WINAPI FiberBinder(void* params) { - auto* fiber_state = static_cast(params); - // Call the main routine from the fiber. Reusing the entry point minimizes - // confusion when examining call stacks in crash reports - seeing wWinMain on - // the stack is a handy hint that this is the main thread of the process. - if (fiber_state->main) { - fiber_state->fiber_result = - fiber_state->main(fiber_state->argc, fiber_state->argv); - } else { - fiber_state->fiber_result = - fiber_state->wWinMain(fiber_state->hInstance, nullptr, - fiber_state->lpCmdLine, fiber_state->nCmdShow); - } - - // Switch back to the main thread to exit. - ::SwitchToFiber(fiber_state->original_fiber); -} - -int RunMainWithPreferredStackSize(FiberState& fiber_state) { - enum class FiberStatus { kConvertFailed, kCreateFiberFailed, kSuccess }; - FiberStatus fiber_status = FiberStatus::kSuccess; - // GetLastError result if fiber conversion failed. - DWORD fiber_error = ERROR_SUCCESS; - if (!::IsThreadAFiber()) { - // Make the main thread's stack size 4 MiB so that it has roughly the same - // effective size as the 64-bit build's 8 MiB stack. - constexpr size_t kStackSize = 4 * 1024 * 1024; // 4 MiB - // Leak the fiber on exit. - LPVOID original_fiber = - ::ConvertThreadToFiberEx(nullptr, FIBER_FLAG_FLOAT_SWITCH); - if (original_fiber) { - fiber_state.original_fiber = original_fiber; - // Create a fiber with a bigger stack and switch to it. Leak the fiber on - // exit. - LPVOID big_stack_fiber = ::CreateFiberEx( - 0, kStackSize, FIBER_FLAG_FLOAT_SWITCH, FiberBinder, &fiber_state); - if (big_stack_fiber) { - ::SwitchToFiber(big_stack_fiber); - // The fibers must be cleaned up to avoid obscure TLS-related shutdown - // crashes. - ::DeleteFiber(big_stack_fiber); - ::ConvertFiberToThread(); - // Control returns here after CEF has finished running on FiberMain. - return fiber_state.fiber_result; - } - fiber_status = FiberStatus::kCreateFiberFailed; - } else { - fiber_status = FiberStatus::kConvertFailed; - } - // If we reach here then creating and switching to a fiber has failed. This - // probably means we are low on memory and will soon crash. Try to report - // this error once crash reporting is initialized. - fiber_error = ::GetLastError(); - base::debug::Alias(&fiber_error); - } - - // If we are already a fiber then continue normal execution. - // Intentionally crash if converting to a fiber failed. - CHECK_EQ(fiber_status, FiberStatus::kSuccess); - return -1; -} -#endif // BUILDFLAG(IS_WIN) && defined(ARCH_CPU_32_BITS) - } // namespace NO_STACK_PROTECTOR @@ -418,23 +314,6 @@ void CefQuitMessageLoop() { #if BUILDFLAG(IS_WIN) -#if defined(ARCH_CPU_32_BITS) -int CefRunWinMainWithPreferredStackSize(wWinMainPtr wWinMain, - HINSTANCE hInstance, - LPWSTR lpCmdLine, - int nCmdShow) { - CHECK(wWinMain && hInstance); - FiberState fiber_state(wWinMain, hInstance, lpCmdLine, nCmdShow); - return RunMainWithPreferredStackSize(fiber_state); -} - -int CefRunMainWithPreferredStackSize(mainPtr main, int argc, char* argv[]) { - CHECK(main); - FiberState fiber_state(main, argc, argv); - return RunMainWithPreferredStackSize(fiber_state); -} -#endif // defined(ARCH_CPU_32_BITS) - void CefSetOSModalLoop(bool osModalLoop) { // Verify that the context is in a valid state. if (!CONTEXT_STATE_VALID()) { diff --git a/libcef/browser/preferred_stack_size_win.inc b/libcef/browser/preferred_stack_size_win.inc new file mode 100644 index 000000000..79c8644ff --- /dev/null +++ b/libcef/browser/preferred_stack_size_win.inc @@ -0,0 +1,129 @@ +#include "build/build_config.h" + +// Based on chrome/app/chrome_exe_main_win.cc. +// In 32-bit builds, the main thread starts with the default (small) stack size. +// The ARCH_CPU_32_BITS blocks here and below are in support of moving the main +// thread to a fiber with a larger stack size. +#if BUILDFLAG(IS_WIN) && defined(ARCH_CPU_32_BITS) + +#include "base/debug/alias.h" +#include "include/internal/cef_app_win.h" + +namespace { + +// The information needed to transfer control to the large-stack fiber and later +// pass the main routine's exit code back to the small-stack fiber prior to +// termination. +struct FiberState { + FiberState(wWinMainPtr wWinMain, + HINSTANCE hInstance, + LPWSTR lpCmdLine, + int nCmdShow) { + this->wWinMain = wWinMain; + this->hInstance = hInstance; + this->lpCmdLine = lpCmdLine; + this->nCmdShow = nCmdShow; + } + + FiberState(mainPtr main, int argc, char** argv) { + this->main = main; + this->argc = argc; + this->argv = argv; + } + + wWinMainPtr wWinMain = nullptr; + HINSTANCE hInstance; + LPWSTR lpCmdLine; + int nCmdShow; + + mainPtr main = nullptr; + int argc; + char** argv; + + LPVOID original_fiber; + int fiber_result; +}; + +// A PFIBER_START_ROUTINE function run on a large-stack fiber that calls the +// main routine, stores its return value, and returns control to the small-stack +// fiber. |params| must be a pointer to a FiberState struct. +void WINAPI FiberBinder(void* params) { + auto* fiber_state = static_cast(params); + // Call the main routine from the fiber. Reusing the entry point minimizes + // confusion when examining call stacks in crash reports - seeing wWinMain on + // the stack is a handy hint that this is the main thread of the process. + if (fiber_state->main) { + fiber_state->fiber_result = + fiber_state->main(fiber_state->argc, fiber_state->argv); + } else { + fiber_state->fiber_result = + fiber_state->wWinMain(fiber_state->hInstance, nullptr, + fiber_state->lpCmdLine, fiber_state->nCmdShow); + } + + // Switch back to the main thread to exit. + ::SwitchToFiber(fiber_state->original_fiber); +} + +int RunMainWithPreferredStackSize(FiberState& fiber_state) { + enum class FiberStatus { kConvertFailed, kCreateFiberFailed, kSuccess }; + FiberStatus fiber_status = FiberStatus::kSuccess; + // GetLastError result if fiber conversion failed. + DWORD fiber_error = ERROR_SUCCESS; + if (!::IsThreadAFiber()) { + // Make the main thread's stack size 4 MiB so that it has roughly the same + // effective size as the 64-bit build's 8 MiB stack. + constexpr size_t kStackSize = 4 * 1024 * 1024; // 4 MiB + // Leak the fiber on exit. + LPVOID original_fiber = + ::ConvertThreadToFiberEx(nullptr, FIBER_FLAG_FLOAT_SWITCH); + if (original_fiber) { + fiber_state.original_fiber = original_fiber; + // Create a fiber with a bigger stack and switch to it. Leak the fiber on + // exit. + LPVOID big_stack_fiber = ::CreateFiberEx( + 0, kStackSize, FIBER_FLAG_FLOAT_SWITCH, FiberBinder, &fiber_state); + if (big_stack_fiber) { + ::SwitchToFiber(big_stack_fiber); + // The fibers must be cleaned up to avoid obscure TLS-related shutdown + // crashes. + ::DeleteFiber(big_stack_fiber); + ::ConvertFiberToThread(); + // Control returns here after CEF has finished running on FiberMain. + return fiber_state.fiber_result; + } + fiber_status = FiberStatus::kCreateFiberFailed; + } else { + fiber_status = FiberStatus::kConvertFailed; + } + // If we reach here then creating and switching to a fiber has failed. This + // probably means we are low on memory and will soon crash. Try to report + // this error once crash reporting is initialized. + fiber_error = ::GetLastError(); + base::debug::Alias(&fiber_error); + } + + // If we are already a fiber then continue normal execution. + // Intentionally crash if converting to a fiber failed. + CHECK_EQ(fiber_status, FiberStatus::kSuccess); + return -1; +} + +} // namespace + +int CefRunWinMainWithPreferredStackSize(wWinMainPtr wWinMain, + HINSTANCE hInstance, + LPWSTR lpCmdLine, + int nCmdShow) { + CHECK(wWinMain && hInstance); + FiberState fiber_state(wWinMain, hInstance, lpCmdLine, nCmdShow); + return RunMainWithPreferredStackSize(fiber_state); +} + +int CefRunMainWithPreferredStackSize(mainPtr main, int argc, char* argv[]) { + CHECK(main); + FiberState fiber_state(main, argc, argv); + return RunMainWithPreferredStackSize(fiber_state); +} + +#endif // BUILDFLAG(IS_WIN) && defined(ARCH_CPU_32_BITS) diff --git a/libcef_dll/bootstrap/bootstrap_util_win.cc b/libcef_dll/bootstrap/bootstrap_util_win.cc new file mode 100644 index 000000000..86c10f763 --- /dev/null +++ b/libcef_dll/bootstrap/bootstrap_util_win.cc @@ -0,0 +1,82 @@ +// Copyright (c) 2025 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#include "cef/libcef_dll/bootstrap/bootstrap_util_win.h" + +#include "base/check_op.h" +#include "base/command_line.h" + +namespace bootstrap_util { + +namespace { + +constexpr wchar_t kWindowsSelfName[] = TEXT("bootstrap"); +constexpr wchar_t kConsoleSelfName[] = TEXT("bootstrapc"); + +// Returns the file name only without extension, if any. +inline std::wstring NamePart(const base::FilePath& path) { + return path.BaseName().RemoveExtension().value(); +} + +} // namespace + +bool IsDefaultExeName(const std::wstring& name) { + return base::FilePath::CompareEqualIgnoreCase(name, kWindowsSelfName) || + base::FilePath::CompareEqualIgnoreCase(name, kConsoleSelfName); +} + +std::wstring GetModuleValue(const base::CommandLine& command_line) { + if (command_line.HasSwitch(switches::kModule)) { + const auto& value = command_line.GetSwitchValuePath(switches::kModule); + if (!value.empty()) { + return NamePart(value); + } + } + + return std::wstring(); +} + +base::FilePath GetExePath() { + HMODULE hModule = ::GetModuleHandle(nullptr); + CHECK(hModule); + return GetModulePath(hModule); +} + +base::FilePath GetModulePath(HMODULE module) { + wchar_t buffer[MAX_PATH]; + DWORD length = ::GetModuleFileName(module, buffer, MAX_PATH); + CHECK_NE(length, 0U); + CHECK_LT(length, static_cast(MAX_PATH)); + + return base::FilePath(buffer); +} + +std::wstring GetValidatedModuleValue(const base::CommandLine& command_line, + const base::FilePath& exe_path) { + // Allow module value configuration if the bootstrap executable has the + // default name. + const auto& value = GetModuleValue(command_line); + if (!value.empty() && IsDefaultExeName(NamePart(exe_path))) { + return value; + } + return std::wstring(); +} + +std::wstring GetDefaultModuleValue(const base::FilePath& exe_path) { + return NamePart(exe_path); +} + +bool IsModulePathAllowed(HMODULE module, const base::FilePath& exe_path) { + // Allow any module path if the bootstrap executable has the default name. + if (IsDefaultExeName(NamePart(exe_path))) { + return true; + } + + const auto& module_path = GetModulePath(module); + + // Module must be at the same path as the executable. + return module_path.DirName() == exe_path.DirName(); +} + +} // namespace bootstrap_util diff --git a/libcef_dll/bootstrap/bootstrap_util_win.h b/libcef_dll/bootstrap/bootstrap_util_win.h new file mode 100644 index 000000000..746d206f8 --- /dev/null +++ b/libcef_dll/bootstrap/bootstrap_util_win.h @@ -0,0 +1,51 @@ +// Copyright (c) 2025 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#ifndef CEF_LIBCEF_DLL_BOOTSTRAP_BOOTSTRAP_UTIL_WIN_H_ +#define CEF_LIBCEF_DLL_BOOTSTRAP_BOOTSTRAP_UTIL_WIN_H_ +#pragma once + +#include + +#include + +#include "base/files/file_path.h" + +namespace base { +class CommandLine; +} + +namespace bootstrap_util { + +namespace switches { +inline constexpr char kModule[] = "module"; +} + +// Returns true if |name| is one of the default bootstrap executable names. +bool IsDefaultExeName(const std::wstring& name); + +// Returns the command-line configured module value without validation. +std::wstring GetModuleValue(const base::CommandLine& command_line); + +// The following functions can only be called in unsandboxed processes. + +// Returns the fully qualified file path for the executable module. +base::FilePath GetExePath(); + +// Returns the fully qualified file path for |module|. +base::FilePath GetModulePath(HMODULE module); + +// Returns the command-line configured module value if it passes validation. +std::wstring GetValidatedModuleValue(const base::CommandLine& command_line, + const base::FilePath& exe_path); + +// Returns the default module name (executable name without extension). +std::wstring GetDefaultModuleValue(const base::FilePath& exe_path); + +// Returns true if loading |module| is allowed. +bool IsModulePathAllowed(HMODULE module, const base::FilePath& exe_path); + +} // namespace bootstrap_util + +#endif // CEF_LIBCEF_DLL_BOOTSTRAP_BOOTSTRAP_UTIL_WIN_H_ diff --git a/libcef_dll/bootstrap/bootstrap_win.cc b/libcef_dll/bootstrap/bootstrap_win.cc new file mode 100644 index 000000000..e0fc2bbd7 --- /dev/null +++ b/libcef_dll/bootstrap/bootstrap_win.cc @@ -0,0 +1,179 @@ +// Copyright (c) 2025 The Chromium Embedded Framework Authors. All rights +// reserved. Use of this source code is governed by a BSD-style license that +// can be found in the LICENSE file. + +#include + +#include + +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/process/process_info.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" +#include "cef/include/cef_sandbox_win.h" +#include "cef/libcef/browser/preferred_stack_size_win.inc" +#include "cef/libcef_dll/bootstrap/bootstrap_util_win.h" +#include "cef/libcef_dll/bootstrap/win/resource.h" + +namespace { + +// Load a string from the string table in bootstrap.rc. +std::wstring LoadString(int string_id) { + const int kMaxSize = 100; + TCHAR buff[kMaxSize] = {0}; + ::LoadString(::GetModuleHandle(nullptr), string_id, buff, kMaxSize); + return buff; +} + +// Replace $1-$2-$3..$9 in the format string with values from |subst|. +// Additionally, any number of consecutive '$' characters is replaced by that +// number less one. Eg $$->$, $$$->$$, etc. Supports up to 9 replacements. +std::wstring FormatErrorString(int string_id, + base::span subst) { + return base::UTF16ToWide(base::ReplaceStringPlaceholders( + base::WideToUTF16(LoadString(string_id)), subst, nullptr)); +} + +void ShowError(const std::wstring& error) { + const auto subst = std::to_array( + {base::WideToUTF16(bootstrap_util::GetExePath().BaseName().value())}); + const auto& title = FormatErrorString(IDS_ERROR_TITLE, subst); + const auto& extra_info = LoadString(IDS_ERROR_EXTRA_INFO); + +#if defined(CEF_BUILD_BOOTSTRAP_CONSOLE) + std::wcerr << title.c_str() << ": " << error << extra_info; +#else + const std::wstring& msg = error + extra_info; + ::MessageBox(nullptr, msg.c_str(), title.c_str(), MB_ICONERROR | MB_OK); +#endif +} + +} // namespace + +#if defined(CEF_BUILD_BOOTSTRAP_CONSOLE) +int main(int argc, char* argv[]) { +#else // !defined(CEF_BUILD_BOOTSTRAP_CONSOLE) +// Entry point function for all processes. +int APIENTRY wWinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPTSTR lpCmdLine, + int nCmdShow) { + UNREFERENCED_PARAMETER(hPrevInstance); + UNREFERENCED_PARAMETER(lpCmdLine); +#endif // !defined(CEF_BUILD_BOOTSTRAP_CONSOLE) + +#if defined(ARCH_CPU_32_BITS) + // Run the main thread on 32-bit Windows using a fiber with the preferred 4MiB + // stack size. This function must be called at the top of the executable entry + // point function (`main()` or `wWinMain()`). It is used in combination with + // the initial stack size of 0.5MiB configured via the `/STACK:0x80000` linker + // flag on executable targets. This saves significant memory on threads (like + // those in the Windows thread pool, and others) whose stack size can only be + // controlled via the linker flag. +#if defined(CEF_BUILD_BOOTSTRAP_CONSOLE) + int exit_code = CefRunMainWithPreferredStackSize(main, argc, argv); +#else + int exit_code = CefRunWinMainWithPreferredStackSize(wWinMain, hInstance, + lpCmdLine, nCmdShow); +#endif + if (exit_code >= 0) { + // The fiber has completed so return here. + return exit_code; + } +#endif + + // Parse command-line arguments. + const base::CommandLine command_line = + base::CommandLine::FromString(::GetCommandLineW()); + + // True if this is a sandboxed sub-process. Uses similar logic to + // Sandbox::IsProcessSandboxed. + const bool is_sandboxed = + command_line.HasSwitch("type") && + base::GetCurrentProcessIntegrityLevel() < base::MEDIUM_INTEGRITY; + + std::wstring dll_name; + base::FilePath exe_path; + + if (is_sandboxed) { + // Running as a sandboxed sub-process. May already be locked down, so we + // can't call WinAPI functions. The command-line will already have been + // validated in ChromeContentBrowserClientCef:: + // AppendExtraCommandLineSwitches. Retrieve the module value without + // additional validation. + dll_name = bootstrap_util::GetModuleValue(command_line); + if (dll_name.empty()) { + // Default to the command-line program name without extension. + dll_name = command_line.GetProgram().BaseName().RemoveExtension().value(); + } + } else { + // Running as the main process or unsandboxed sub-process. + exe_path = bootstrap_util::GetExePath(); + + // Retrieve the module name with validation. + dll_name = bootstrap_util::GetValidatedModuleValue(command_line, exe_path); + if (dll_name.empty()) { + // Default to the executable module file name without extension. This is + // safer than relying on the command-line program name. + dll_name = bootstrap_util::GetDefaultModuleValue(exe_path); + } + + if (bootstrap_util::IsDefaultExeName(dll_name)) { + ShowError(LoadString(IDS_ERROR_NO_MODULE_NAME)); + return 1; + } + } + + // Manage the life span of the sandbox information object. This is necessary + // for sandbox support on Windows. See cef_sandbox_win.h for complete details. + CefScopedSandboxInfo scoped_sandbox; + void* sandbox_info = scoped_sandbox.sandbox_info(); + +#if defined(CEF_BUILD_BOOTSTRAP_CONSOLE) + constexpr char kProcName[] = "RunConsoleMain"; + using kProcType = decltype(&RunConsoleMain); +#else + constexpr char kProcName[] = "RunWinMain"; + using kProcType = decltype(&RunWinMain); +#endif + + std::wstring error; + + if (HMODULE hModule = ::LoadLibrary(dll_name.c_str())) { + if (is_sandboxed || + bootstrap_util::IsModulePathAllowed(hModule, exe_path)) { + if (auto* pFunc = (kProcType)::GetProcAddress(hModule, kProcName)) { +#if defined(CEF_BUILD_BOOTSTRAP_CONSOLE) + return pFunc(argc, argv, sandbox_info); +#else + return pFunc(hInstance, lpCmdLine, nCmdShow, sandbox_info); +#endif + } else if (!is_sandboxed) { + const auto subst = std::to_array( + {base::WideToUTF16(dll_name), + base::NumberToString16(::GetLastError()), + base::ASCIIToUTF16(std::string(kProcName))}); + error = FormatErrorString(IDS_ERROR_NO_PROC_EXPORT, subst); + } + } else if (!is_sandboxed) { + const auto subst = + std::to_array({base::WideToUTF16(dll_name)}); + error = FormatErrorString(IDS_ERROR_INVALID_LOCATION, subst); + } + FreeLibrary(hModule); + } else if (!is_sandboxed) { + const auto subst = std::to_array( + {base::WideToUTF16(dll_name), + base::NumberToString16(::GetLastError())}); + error = FormatErrorString(IDS_ERROR_LOAD_FAILED, subst); + } + + // Don't try to show errors while sandboxed. + if (!error.empty() && !is_sandboxed) { + ShowError(error); + } + + return 1; +} diff --git a/libcef_dll/bootstrap/win/bootstrap.ico b/libcef_dll/bootstrap/win/bootstrap.ico new file mode 100644 index 0000000000000000000000000000000000000000..d551aa3aaf80adf9b7760e2eb8de95a5c3e53df6 GIT binary patch literal 23558 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 zZGetBackgroundColor(); const HBRUSH background_brush = CreateSolidBrush( diff --git a/tests/cefclient/browser/root_window_win.cc b/tests/cefclient/browser/root_window_win.cc index e7f5615aa..6572677c2 100644 --- a/tests/cefclient/browser/root_window_win.cc +++ b/tests/cefclient/browser/root_window_win.cc @@ -487,7 +487,7 @@ void RootWindowWin::CreateRootWindow(const CefBrowserSettings& settings, REQUIRE_MAIN_THREAD(); DCHECK(!hwnd_); - HINSTANCE hInstance = GetModuleHandle(nullptr); + HINSTANCE hInstance = GetCodeModuleHandle(); // Load strings from the resource file. const std::wstring& window_title = GetResourceString(IDS_APP_TITLE); @@ -1079,7 +1079,7 @@ void RootWindowWin::OnFindEvent() { void RootWindowWin::OnAbout() { // Show the about box. - DialogBox(GetModuleHandle(nullptr), MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd_, + DialogBox(GetCodeModuleHandle(), MAKEINTRESOURCE(IDD_ABOUTBOX), hwnd_, AboutWndProc); } diff --git a/tests/cefclient/browser/temp_window_win.cc b/tests/cefclient/browser/temp_window_win.cc index aacb80eb6..39191953f 100644 --- a/tests/cefclient/browser/temp_window_win.cc +++ b/tests/cefclient/browser/temp_window_win.cc @@ -7,6 +7,7 @@ #include #include "include/base/cef_logging.h" +#include "tests/shared/browser/util_win.h" namespace client { @@ -16,7 +17,7 @@ const wchar_t kWndClass[] = L"Client_TempWindow"; // Create the temp window. HWND CreateTempWindow() { - HINSTANCE hInstance = ::GetModuleHandle(nullptr); + HINSTANCE hInstance = GetCodeModuleHandle(); WNDCLASSEX wc = {0}; wc.cbSize = sizeof(wc); diff --git a/tests/cefclient/cefclient_win.cc b/tests/cefclient/cefclient_win.cc index 252dc2849..1112341b1 100644 --- a/tests/cefclient/cefclient_win.cc +++ b/tests/cefclient/cefclient_win.cc @@ -20,33 +20,12 @@ #include "tests/shared/common/client_switches.h" #include "tests/shared/renderer/client_app_renderer.h" -// When generating projects with CMake the CEF_USE_SANDBOX value will be defined -// automatically if using the required compiler version. Pass -DUSE_SANDBOX=OFF -// to the CMake command-line to disable use of the sandbox. -// Uncomment this line to manually enable sandbox support. -// #define CEF_USE_SANDBOX 1 - -#if defined(CEF_USE_SANDBOX) -// The cef_sandbox.lib static library may not link successfully with all VS -// versions. -#pragma comment(lib, "cef_sandbox.lib") -#endif - namespace client { namespace { -int RunMain(HINSTANCE hInstance, int nCmdShow) { +int RunMain(HINSTANCE hInstance, int nCmdShow, void* sandbox_info) { CefMainArgs main_args(hInstance); - void* sandbox_info = nullptr; - -#if defined(CEF_USE_SANDBOX) - // Manage the life span of the sandbox information object. This is necessary - // for sandbox support on Windows. See cef_sandbox_win.h for complete details. - CefScopedSandboxInfo scoped_sandbox; - sandbox_info = scoped_sandbox.sandbox_info(); -#endif - // Parse command-line arguments. CefRefPtr command_line = CefCommandLine::CreateCommandLine(); command_line->InitFromString(::GetCommandLineW()); @@ -73,9 +52,9 @@ int RunMain(HINSTANCE hInstance, int nCmdShow) { CefSettings settings; -#if !defined(CEF_USE_SANDBOX) - settings.no_sandbox = true; -#endif + if (!sandbox_info) { + settings.no_sandbox = true; + } // Populate the settings based on command line arguments. context->PopulateSettings(&settings); @@ -131,6 +110,18 @@ int RunMain(HINSTANCE hInstance, int nCmdShow) { } // namespace } // namespace client +#if defined(CEF_USE_BOOTSTRAP) + +// Entry point called by bootstrap.exe when built as a DLL. +CEF_BOOTSTRAP_EXPORT int RunWinMain(HINSTANCE hInstance, + LPTSTR lpCmdLine, + int nCmdShow, + void* sandbox_info) { + return client::RunMain(hInstance, nCmdShow, sandbox_info); +} + +#else // !defined(CEF_USE_BOOTSTRAP) + // Program entry point function. int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, @@ -155,5 +146,16 @@ int APIENTRY wWinMain(HINSTANCE hInstance, } #endif - return client::RunMain(hInstance, nCmdShow); + void* sandbox_info = nullptr; + +#if defined(CEF_USE_SANDBOX) + // Manage the life span of the sandbox information object. This is necessary + // for sandbox support on Windows. See cef_sandbox_win.h for complete details. + CefScopedSandboxInfo scoped_sandbox; + sandbox_info = scoped_sandbox.sandbox_info(); +#endif + + return client::RunMain(hInstance, nCmdShow, sandbox_info); } + +#endif // !defined(CEF_USE_BOOTSTRAP) diff --git a/tests/cefsimple/cefsimple_win.cc b/tests/cefsimple/cefsimple_win.cc index 1ee933a89..95aa8cc5f 100644 --- a/tests/cefsimple/cefsimple_win.cc +++ b/tests/cefsimple/cefsimple_win.cc @@ -8,53 +8,14 @@ #include "include/cef_sandbox_win.h" #include "tests/cefsimple/simple_app.h" -// When generating projects with CMake the CEF_USE_SANDBOX value will be defined -// automatically if using the required compiler version. Pass -DUSE_SANDBOX=OFF -// to the CMake command-line to disable use of the sandbox. -// Uncomment this line to manually enable sandbox support. -// #define CEF_USE_SANDBOX 1 - -#if defined(CEF_USE_SANDBOX) -// The cef_sandbox.lib static library may not link successfully with all VS -// versions. -#pragma comment(lib, "cef_sandbox.lib") -#endif - -// Entry point function for all processes. -int APIENTRY wWinMain(HINSTANCE hInstance, - HINSTANCE hPrevInstance, - LPTSTR lpCmdLine, - int nCmdShow) { - UNREFERENCED_PARAMETER(hPrevInstance); - UNREFERENCED_PARAMETER(lpCmdLine); +namespace { +int RunMain(HINSTANCE hInstance, + LPTSTR lpCmdLine, + int nCmdShow, + void* sandbox_info) { int exit_code; -#if defined(ARCH_CPU_32_BITS) - // Run the main thread on 32-bit Windows using a fiber with the preferred 4MiB - // stack size. This function must be called at the top of the executable entry - // point function (`main()` or `wWinMain()`). It is used in combination with - // the initial stack size of 0.5MiB configured via the `/STACK:0x80000` linker - // flag on executable targets. This saves significant memory on threads (like - // those in the Windows thread pool, and others) whose stack size can only be - // controlled via the linker flag. - exit_code = CefRunWinMainWithPreferredStackSize(wWinMain, hInstance, - lpCmdLine, nCmdShow); - if (exit_code >= 0) { - // The fiber has completed so return here. - return exit_code; - } -#endif - - void* sandbox_info = nullptr; - -#if defined(CEF_USE_SANDBOX) - // Manage the life span of the sandbox information object. This is necessary - // for sandbox support on Windows. See cef_sandbox_win.h for complete details. - CefScopedSandboxInfo scoped_sandbox; - sandbox_info = scoped_sandbox.sandbox_info(); -#endif - // Provide CEF with command-line arguments. CefMainArgs main_args(hInstance); @@ -74,9 +35,9 @@ int APIENTRY wWinMain(HINSTANCE hInstance, // Specify CEF global settings here. CefSettings settings; -#if !defined(CEF_USE_SANDBOX) - settings.no_sandbox = true; -#endif + if (!sandbox_info) { + settings.no_sandbox = true; + } // SimpleApp implements application-level callbacks for the browser process. // It will create the first browser instance in OnContextInitialized() after @@ -99,3 +60,55 @@ int APIENTRY wWinMain(HINSTANCE hInstance, return 0; } + +} // namespace + +#if defined(CEF_USE_BOOTSTRAP) + +// Entry point called by bootstrap.exe when built as a DLL. +CEF_BOOTSTRAP_EXPORT int RunWinMain(HINSTANCE hInstance, + LPTSTR lpCmdLine, + int nCmdShow, + void* sandbox_info) { + return ::RunMain(hInstance, lpCmdLine, nCmdShow, sandbox_info); +} + +#else // !defined(CEF_USE_BOOTSTRAP) + +// Entry point function for all processes. +int APIENTRY wWinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPTSTR lpCmdLine, + int nCmdShow) { + UNREFERENCED_PARAMETER(hPrevInstance); + UNREFERENCED_PARAMETER(lpCmdLine); + +#if defined(ARCH_CPU_32_BITS) + // Run the main thread on 32-bit Windows using a fiber with the preferred 4MiB + // stack size. This function must be called at the top of the executable entry + // point function (`main()` or `wWinMain()`). It is used in combination with + // the initial stack size of 0.5MiB configured via the `/STACK:0x80000` linker + // flag on executable targets. This saves significant memory on threads (like + // those in the Windows thread pool, and others) whose stack size can only be + // controlled via the linker flag. + int exit_code = CefRunWinMainWithPreferredStackSize(wWinMain, hInstance, + lpCmdLine, nCmdShow); + if (exit_code >= 0) { + // The fiber has completed so return here. + return exit_code; + } +#endif + + void* sandbox_info = nullptr; + +#if defined(CEF_USE_SANDBOX) + // Manage the life span of the sandbox information object. This is necessary + // for sandbox support on Windows. See cef_sandbox_win.h for complete details. + CefScopedSandboxInfo scoped_sandbox; + sandbox_info = scoped_sandbox.sandbox_info(); +#endif + + return ::RunMain(hInstance, lpCmdLine, nCmdShow, sandbox_info); +} + +#endif // !defined(CEF_USE_BOOTSTRAP) diff --git a/tests/ceftests/os_rendering_unittest.cc b/tests/ceftests/os_rendering_unittest.cc index 7831b59ad..bbb7fc0f5 100644 --- a/tests/ceftests/os_rendering_unittest.cc +++ b/tests/ceftests/os_rendering_unittest.cc @@ -21,8 +21,10 @@ #elif defined(OS_LINUX) #include #elif defined(OS_WIN) +#include "tests/shared/browser/util_win.h" + // Required for resource_util_win, which uses this as an extern -HINSTANCE hInst = ::GetModuleHandle(nullptr); +HINSTANCE hInst = client::GetCodeModuleHandle(); #endif // Set to 1 to enable verbose debugging info logging. diff --git a/tests/ceftests/run_all_unittests.cc b/tests/ceftests/run_all_unittests.cc index a74350c04..7bdef18b3 100644 --- a/tests/ceftests/run_all_unittests.cc +++ b/tests/ceftests/run_all_unittests.cc @@ -39,15 +39,9 @@ #include "include/wrapper/cef_library_loader.h" #endif -// When generating projects with CMake the CEF_USE_SANDBOX value will be defined -// automatically if using the required compiler version. Pass -DUSE_SANDBOX=OFF -// to the CMake command-line to disable use of the sandbox. -#if defined(OS_WIN) && defined(CEF_USE_SANDBOX) +#if defined(OS_WIN) #include "include/cef_sandbox_win.h" - -// The cef_sandbox.lib static library may not link successfully with all VS -// versions. -#pragma comment(lib, "cef_sandbox.lib") +#include "tests/shared/browser/util_win.h" #endif #if defined(OS_MAC) @@ -132,31 +126,13 @@ class ScopedPlatformSetup final { }; #endif // defined(OS_MAC) -} // namespace - -NO_STACK_PROTECTOR -int main(int argc, char* argv[]) { +int RunMain(int argc, char* argv[], void* sandbox_info) { int exit_code; #if CEF_API_VERSION != CEF_EXPERIMENTAL printf("Running with configured CEF API version %d\n", CEF_API_VERSION); #endif -#if defined(OS_WIN) && defined(ARCH_CPU_32_BITS) - // Run the main thread on 32-bit Windows using a fiber with the preferred 4MiB - // stack size. This function must be called at the top of the executable entry - // point function (`main()` or `wWinMain()`). It is used in combination with - // the initial stack size of 0.5MiB configured via the `/STACK:0x80000` linker - // flag on executable targets. This saves significant memory on threads (like - // those in the Windows thread pool, and others) whose stack size can only be - // controlled via the linker flag. - exit_code = CefRunMainWithPreferredStackSize(main, argc, argv); - if (exit_code >= 0) { - // The fiber has completed so return here. - return exit_code; - } -#endif - #if defined(OS_MAC) // Load the CEF framework library at runtime instead of linking directly // as required by the macOS sandbox implementation. @@ -170,19 +146,11 @@ int main(int argc, char* argv[]) { CefTestSuite test_suite(argc, argv); #if defined(OS_WIN) - CefMainArgs main_args(::GetModuleHandle(nullptr)); + CefMainArgs main_args(client::GetCodeModuleHandle()); #else CefMainArgs main_args(argc, argv); #endif - void* windows_sandbox_info = nullptr; - -#if defined(OS_WIN) && defined(CEF_USE_SANDBOX) - // Manages the life span of the sandbox information object. - CefScopedSandboxInfo scoped_sandbox; - windows_sandbox_info = scoped_sandbox.sandbox_info(); -#endif - // Create a ClientApp of the correct type. CefRefPtr app; client::ClientApp::ProcessType process_type = @@ -198,7 +166,7 @@ int main(int argc, char* argv[]) { } // Execute the secondary process, if any. - exit_code = CefExecuteProcess(main_args, app, windows_sandbox_info); + exit_code = CefExecuteProcess(main_args, app, sandbox_info); if (exit_code >= 0) { return exit_code; } @@ -211,7 +179,11 @@ int main(int argc, char* argv[]) { CefSettings settings; -#if !defined(CEF_USE_SANDBOX) +#if defined(OS_WIN) + if (!sandbox_info) { + settings.no_sandbox = true; + } +#elif !defined(CEF_USE_SANDBOX) settings.no_sandbox = true; #endif @@ -231,7 +203,7 @@ int main(int argc, char* argv[]) { #endif // Initialize CEF. - if (!CefInitialize(main_args, settings, app, windows_sandbox_info)) { + if (!CefInitialize(main_args, settings, app, sandbox_info)) { exit_code = CefGetExitCode(); LOG(ERROR) << "CefInitialize exited with code " << exit_code; return exit_code; @@ -304,3 +276,47 @@ int main(int argc, char* argv[]) { return retval; } + +} // namespace + +#if defined(OS_WIN) && defined(CEF_USE_BOOTSTRAP) + +// Entry point called by bootstrapc.exe when built as a DLL. +CEF_BOOTSTRAP_EXPORT int RunConsoleMain(int argc, + char* argv[], + void* sandbox_info) { + return ::RunMain(argc, argv, sandbox_info); +} + +#else // !(defined(OS_WIN) && defined(CEF_USE_BOOTSTRAP)) + +// Program entry point function. +NO_STACK_PROTECTOR +int main(int argc, char* argv[]) { +#if defined(OS_WIN) && defined(ARCH_CPU_32_BITS) + // Run the main thread on 32-bit Windows using a fiber with the preferred 4MiB + // stack size. This function must be called at the top of the executable entry + // point function (`main()` or `wWinMain()`). It is used in combination with + // the initial stack size of 0.5MiB configured via the `/STACK:0x80000` linker + // flag on executable targets. This saves significant memory on threads (like + // those in the Windows thread pool, and others) whose stack size can only be + // controlled via the linker flag. + exit_code = CefRunMainWithPreferredStackSize(main, argc, argv); + if (exit_code >= 0) { + // The fiber has completed so return here. + return exit_code; + } +#endif + + void* sandbox_info = nullptr; + +#if defined(OS_WIN) && defined(CEF_USE_SANDBOX) + // Manages the life span of the sandbox information object. + CefScopedSandboxInfo scoped_sandbox; + sandbox_info = scoped_sandbox.sandbox_info(); +#endif + + return ::RunMain(argc, argv, sandbox_info); +} + +#endif // !(defined(OS_WIN) && defined(CEF_USE_BOOTSTRAP)) diff --git a/tests/shared/browser/main_message_loop_external_pump_win.cc b/tests/shared/browser/main_message_loop_external_pump_win.cc index e8c0546ef..dd1971caa 100644 --- a/tests/shared/browser/main_message_loop_external_pump_win.cc +++ b/tests/shared/browser/main_message_loop_external_pump_win.cc @@ -51,7 +51,7 @@ class MainMessageLoopExternalPumpWin : public MainMessageLoopExternalPump { }; MainMessageLoopExternalPumpWin::MainMessageLoopExternalPumpWin() { - HINSTANCE hInstance = GetModuleHandle(nullptr); + HINSTANCE hInstance = GetCodeModuleHandle(); const wchar_t* const kClassName = L"CEFMainTargetHWND"; WNDCLASSEX wcex = {}; diff --git a/tests/shared/browser/resource_util_win.cc b/tests/shared/browser/resource_util_win.cc index df61ca122..a438ca83c 100644 --- a/tests/shared/browser/resource_util_win.cc +++ b/tests/shared/browser/resource_util_win.cc @@ -8,13 +8,14 @@ #include "include/cef_stream.h" #include "include/wrapper/cef_byte_read_handler.h" #include "include/wrapper/cef_stream_resource_handler.h" +#include "tests/shared/browser/util_win.h" namespace client { namespace { bool LoadBinaryResource(int binaryId, DWORD& dwSize, LPBYTE& pBytes) { - HINSTANCE hInst = GetModuleHandle(nullptr); + HINSTANCE hInst = GetCodeModuleHandle(); HRSRC hRes = FindResource(hInst, MAKEINTRESOURCE(binaryId), MAKEINTRESOURCE(256)); if (hRes) { diff --git a/tests/shared/browser/util_win.cc b/tests/shared/browser/util_win.cc index 4db8201e4..9eb39ece9 100644 --- a/tests/shared/browser/util_win.cc +++ b/tests/shared/browser/util_win.cc @@ -44,7 +44,7 @@ WNDPROC SetWndProcPtr(HWND hWnd, WNDPROC wndProc) { std::wstring GetResourceString(UINT id) { #define MAX_LOADSTRING 100 TCHAR buff[MAX_LOADSTRING] = {0}; - LoadString(::GetModuleHandle(nullptr), id, buff, MAX_LOADSTRING); + LoadString(GetCodeModuleHandle(), id, buff, MAX_LOADSTRING); return buff; } @@ -191,4 +191,13 @@ float GetDeviceScaleFactor() { return scale_factor; } +HINSTANCE GetCodeModuleHandle() { + HMODULE hModule = nullptr; + CHECK(::GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + reinterpret_cast(GetCodeModuleHandle), + &hModule)); + return hModule; +} + } // namespace client diff --git a/tests/shared/browser/util_win.h b/tests/shared/browser/util_win.h index 1723b4da4..8ef74d820 100644 --- a/tests/shared/browser/util_win.h +++ b/tests/shared/browser/util_win.h @@ -40,6 +40,10 @@ bool IsKeyDown(WPARAM wparam); // return 2.0. float GetDeviceScaleFactor(); +// Returns the module handle that contains this code. When built as a DLL this +// will be the DLL handle instead of the EXE handle. +HINSTANCE GetCodeModuleHandle(); + } // namespace client #endif // CEF_TESTS_SHARED_BROWSER_UTIL_WIN_H_ diff --git a/tools/automate/automate-git.py b/tools/automate/automate-git.py index 1e45fde2b..58a8ee31c 100644 --- a/tools/automate/automate-git.py +++ b/tools/automate/automate-git.py @@ -16,13 +16,11 @@ import sys import tempfile import zipfile -is_python2 = sys.version_info.major == 2 +if sys.version_info.major != 3: + sys.stderr.write('Python3 is required!') + sys.exit(1) -if is_python2: - from urllib import FancyURLopener - from urllib2 import urlopen -else: - from urllib.request import FancyURLopener, urlopen +from urllib.request import FancyURLopener, urlopen ## # Default URLs. @@ -218,19 +216,12 @@ def read_file(path): raise Exception("Path does not exist: %s" % (path)) -def write_fp(fp, data): - if is_python2: - fp.write(data.decode('utf-8')) - else: - fp.write(data) - - def write_file(path, data): """ Write a file. """ msg('Writing %s' % path) if not options.dryrun: with open(path, 'w', encoding='utf-8') as fp: - write_fp(fp, data) + fp.write(data) def read_config_file(path): @@ -446,21 +437,20 @@ def check_pattern_matches(output_file=None): if not skip: if write_msg: if has_output: - write_fp(fp, '\n') - write_fp(fp, - '!!!! WARNING: FOUND PATTERN: %s\n' % entry['pattern']) + fp.write('\n') + fp.write('!!!! WARNING: FOUND PATTERN: %s\n' % entry['pattern']) if 'message' in entry: - write_fp(fp, entry['message'] + '\n') - write_fp(fp, '\n') + fp.write(entry['message'] + '\n') + fp.write('\n') write_msg = False - write_fp(fp, line + '\n') + fp.write(line + '\n') has_output = True if not output_file is None: if has_output: msg('ERROR Matches found. See %s for output.' % out_file) else: - write_fp(fp, 'Good news! No matches.\n') + fp.write('Good news! No matches.\n') fp.close() if has_output: @@ -901,27 +891,13 @@ if not branch_is_master: sys.exit(1) # Verify the minimum supported branch number. - if int(cef_branch) < 3071: + if int(cef_branch) < 5060: print('The requested branch (%s) is too old to build using this tool. ' + 'The minimum supported branch is 3071.' % cef_branch) sys.exit(1) -# True if the requested branch is 3538 or newer. -branch_is_3538_or_newer = (branch_is_master or int(cef_branch) >= 3538) - -# True if the requested branch is 3945 or newer. -branch_is_3945_or_newer = (branch_is_master or int(cef_branch) >= 3945) - -# Enable Python 3 usage in Chromium for branches 3945 and newer. -if branch_is_3945_or_newer and not is_python2 and \ - not 'GCLIENT_PY3' in os.environ.keys(): - os.environ['GCLIENT_PY3'] = '1' - -if not branch_is_3945_or_newer and \ - (not is_python2 or bool(int(os.environ.get('GCLIENT_PY3', '0')))): - print('Python 3 is not supported with branch 3904 and older ' + - '(set GCLIENT_PY3=0 and run with Python 2 executable).') - sys.exit(1) +# True if the requested branch is 7151 or older. +branch_is_7151_or_older = not branch_is_master and int(cef_branch) <= 7151 if options.armbuild: if platform != 'linux': @@ -936,9 +912,9 @@ if platform == 'mac' and not (options.x64build or options.arm64build): sys.exit(1) # Platforms that build a cef_sandbox library. -sandbox_lib_platforms = ['windows'] -if branch_is_3538_or_newer: - sandbox_lib_platforms.append('mac') +sandbox_lib_platforms = ['mac'] +if branch_is_7151_or_older: + sandbox_lib_platforms.append('win') if not platform in sandbox_lib_platforms and (options.sandboxdistrib or options.sandboxdistribonly): @@ -1023,7 +999,7 @@ if platform == 'windows': # Force use of the system installed Git version. git_exe = 'git.exe' # Force use of the Python version bundled with depot_tools. - python_bat = 'python.bat' if is_python2 else 'python3.bat' + python_bat = 'python3.bat' python_exe = os.path.join(depot_tools_dir, python_bat) if options.dryrun and not os.path.exists(python_exe): sys.stdout.write("WARNING: --dry-run assumes that depot_tools" \ @@ -1180,7 +1156,7 @@ if not os.path.exists(gclient_file) or options.forceconfig: msg('Writing %s' % gclient_file) if not options.dryrun: with open(gclient_file, 'w', encoding='utf-8') as fp: - write_fp(fp, gclient_spec) + fp.write(gclient_spec) # Initial Chromium checkout. if not options.nochromiumupdate and not os.path.exists(chromium_src_dir): @@ -1366,6 +1342,8 @@ if not options.nobuild and (chromium_checkout_changed or \ target += ' ' + options.testtarget if platform == 'linux': target += ' chrome_sandbox' + if platform == 'windows' and not branch_is_7151_or_older: + target += ' bootstrap bootstrapc' # Make a CEF Debug build. if not options.nodebugbuild: diff --git a/tools/gclient_hook.py b/tools/gclient_hook.py index ab3968a56..234d3a719 100644 --- a/tools/gclient_hook.py +++ b/tools/gclient_hook.py @@ -66,12 +66,6 @@ if platform == 'windows': # # set WIN_CUSTOM_TOOLCHAIN=1 # - # o Used by tools/msvs_env.bat to configure the MSVS tools environment. - # Should be set to "none" because VC variables for CEF will be set via - # INCLUDE/LIB/PATH. - # - # set CEF_VCVARS=none - # # o Used by the following scripts: # (a) build/vs_toolchain.py SetEnvironmentAndGetRuntimeDllDirs when # determining whether to copy VS runtime binaries to the output directory. diff --git a/tools/gn_args.py b/tools/gn_args.py index b00af9d73..9e5dd0ada 100644 --- a/tools/gn_args.py +++ b/tools/gn_args.py @@ -550,17 +550,6 @@ def GetConfigArgsSandbox(platform, args, is_debug, cpu): 'is_cef_sandbox_build': True, } - if platform == 'windows': - # Avoid Debug build linker errors caused by custom libc++. - add_args['use_custom_libcxx'] = False - - # Avoid dependency on //third_party/perfetto:libperfetto which fails to - # build with MSVC libc++. - add_args['enable_base_tracing'] = False - - # Allow non-component Debug builds for the sandbox. - add_args['forbid_non_component_debug_builds'] = False - if not is_debug: # Disable DCHECKs in Release builds. add_args['dcheck_always_on'] = False @@ -647,8 +636,7 @@ def GetAllPlatformConfigs(build_args, quiet=False): result['Debug_GN_' + cpu] = GetConfigArgs(args, True, cpu) result['Release_GN_' + cpu] = GetConfigArgs(args, False, cpu) - if platform in ('windows', 'mac') and GetArgValue(args, - 'is_official_build'): + if platform == 'mac' and GetArgValue(args, 'is_official_build'): # Build cef_sandbox.lib with a different configuration. if create_debug: result['Debug_GN_' + cpu + '_sandbox'] = GetConfigArgsSandbox( diff --git a/tools/make_distrib.py b/tools/make_distrib.py index af190b90e..fdffeb2f5 100644 --- a/tools/make_distrib.py +++ b/tools/make_distrib.py @@ -561,10 +561,7 @@ def get_undefined_symbols(file): def combine_libs(platform, build_dir, libs, dest_lib): """ Combine multiple static libraries into a single static library. """ intermediate_obj = None - if platform == 'windows': - cmdline = 'msvs_env.bat win%s "%s" combine_libs.py -b "%s" -o "%s"' % ( - platform_arch, sys.executable, build_dir, dest_lib) - elif platform == 'mac': + if platform == 'mac': # Find CEF_EXPORT symbols from libcef_sandbox.a (include/cef_sandbox_mac.h) # Export only symbols that include these strings. symbol_match = [ @@ -589,14 +586,14 @@ def combine_libs(platform, build_dir, libs, dest_lib): cmdline = 'ld -arch %s -r -o "%s"' % (arch, intermediate_obj) for symbol in symbols: cmdline += ' -exported_symbol %s' % symbol + else: + raise Exception('Unsupported platform for combine_libs: %s' % platform) for lib in libs: lib_path = os.path.join(build_dir, lib) for path in get_files(lib_path): # Expand wildcards in |lib_path|. if not path_exists(path): raise Exception('File not found: ' + path) - if platform == 'windows': - path = os.path.relpath(path, build_dir) cmdline += ' "%s"' % path run(cmdline, os.path.join(cef_dir, 'tools')) @@ -746,7 +743,7 @@ parser.add_option( action='store_true', dest='sandbox', default=False, - help='include only the cef_sandbox static library (macOS and Windows only)') + help='include only the cef_sandbox static library (macOS only)') parser.add_option( '--tools', action='store_true', @@ -794,8 +791,8 @@ if options.armbuild and platform != 'linux': print_error('--arm-build is only supported on Linux.') sys.exit() -if options.sandbox and not platform in ('mac', 'windows'): - print_error('--sandbox is only supported on macOS and Windows.') +if options.sandbox and platform != 'mac': + print_error('--sandbox is only supported on macOS.') sys.exit() if not options.ninjabuild: @@ -1130,6 +1127,8 @@ elif platform == 'windows': {'path': 'vulkan-1.dll'}, ] pdb_files = [ + {'path': 'bootstrap.exe.pdb'}, + {'path': 'bootstrapc.exe.pdb'}, {'path': 'chrome_elf.dll.pdb'}, {'path': 'dxcompiler.dll.pdb', 'conditional': True}, {'path': '%s.pdb' % libcef_dll}, @@ -1145,7 +1144,13 @@ elif platform == 'windows': 'path': 'cefsimple.exe' if platform_arch == 'arm64' else 'cefclient.exe' }) else: - binaries.append({'path': '%s.lib' % libcef_dll, 'out_path': 'libcef.lib'}) + # yapf: disable + binaries.extend([ + {'path': 'bootstrap.exe'}, + {'path': 'bootstrapc.exe'}, + {'path': '%s.lib' % libcef_dll, 'out_path': 'libcef.lib'}, + ]) + # yapf: enable # yapf: disable resources = [ @@ -1157,43 +1162,6 @@ elif platform == 'windows': ] # yapf: enable - cef_sandbox_lib = 'obj\\cef\\cef_sandbox.lib' - sandbox_libs = [ - 'obj\\base\\base.lib', - 'obj\\base\\base_static.lib', - 'obj\\base\\third_party\\cityhash\\cityhash\\*.obj', - 'obj\\base\\third_party\\double_conversion\\double_conversion.lib', - 'obj\\base\\third_party\\superfasthash\\superfasthash\\*.obj', - 'obj\\base\\win\\pe_image.lib', - cef_sandbox_lib, - 'obj\\sandbox\\common\\*.obj', - 'obj\\sandbox\\win\\sandbox.lib', - 'obj\\sandbox\\win\\service_resolver\\*.obj', - 'obj\\third_party\\abseil-cpp\\absl\\base\\**\\*.obj', - 'obj\\third_party\\abseil-cpp\\absl\\debugging\\**\\*.obj', - 'obj\\third_party\\abseil-cpp\\absl\\numeric\\**\\*.obj', - 'obj\\third_party\\abseil-cpp\\absl\\strings\\**\\*.obj', - 'obj\\third_party\\abseil-cpp\\absl\\synchronization\\**\\*.obj', - 'obj\\third_party\\abseil-cpp\\absl\\time\\**\\*.obj', - 'obj\\third_party\\abseil-cpp\\absl\\types\\**\\*.obj', - ] - - # Generate the cef_sandbox.lib merged library. A separate *_sandbox build - # should exist when GN is_official_build=true. - if mode in ('standard', 'minimal', 'sandbox') and not options.nosandbox: - dirs = { - 'Debug': (build_dir_debug + '_sandbox', build_dir_debug), - 'Release': (build_dir_release + '_sandbox', build_dir_release) - } - for dir_name in dirs.keys(): - for src_dir in dirs[dir_name]: - if path_exists(os.path.join(src_dir, cef_sandbox_lib)): - dst_dir = os.path.join(output_dir, dir_name) - make_dir(dst_dir, options.quiet) - combine_libs(platform, src_dir, sandbox_libs, - os.path.join(dst_dir, 'cef_sandbox.lib')) - break - valid_build_dir = None if mode == 'standard': @@ -1214,23 +1182,22 @@ elif platform == 'windows': else: sys.stdout.write("No Debug build files.\n") - if mode != 'sandbox': - # transfer Release files - build_dir = build_dir_release - if not options.allowpartial or path_exists( - os.path.join(build_dir, libcef_dll)): - valid_build_dir = build_dir - dst_dir = os.path.join(output_dir, 'Release') - copy_files_list(build_dir, dst_dir, binaries) + # transfer Release files + build_dir = build_dir_release + if not options.allowpartial or path_exists( + os.path.join(build_dir, libcef_dll)): + valid_build_dir = build_dir + dst_dir = os.path.join(output_dir, 'Release') + copy_files_list(build_dir, dst_dir, binaries) - if not options.nosymbols: - # create the symbol output directory - symbol_output_dir = create_output_dir( - output_dir_name + '_release_symbols', options.outputdir) - # transfer contents - copy_files_list(build_dir, symbol_output_dir, pdb_files) - else: - sys.stdout.write("No Release build files.\n") + if not options.nosymbols: + # create the symbol output directory + symbol_output_dir = create_output_dir( + output_dir_name + '_release_symbols', options.outputdir) + # transfer contents + copy_files_list(build_dir, symbol_output_dir, pdb_files) + else: + sys.stdout.write("No Release build files.\n") if not valid_build_dir is None: # transfer resource files diff --git a/tools/msvs_env.bat b/tools/msvs_env.bat deleted file mode 100644 index 8329b7274..000000000 --- a/tools/msvs_env.bat +++ /dev/null @@ -1,73 +0,0 @@ -@echo off -:: Copyright (c) 2013 The Chromium Embedded Framework Authors. All rights -:: reserved. Use of this source code is governed by a BSD-style license -:: that can be found in the LICENSE file. - -:: Set up the environment for use with MSVS tools and then execute whatever -:: was specified on the command-line. - -set RC= - -:: Support !! syntax for delayed variable expansion. -setlocal enabledelayedexpansion - -:: Require that platform is passed as the first argument. -if "%1" == "win32" ( - set vcvarsbat=vcvars32.bat -) else if "%1" == "win64" ( - set vcvarsbat=vcvars64.bat -) else if "%1" == "winarm64" ( - set vcvarsbat=vcvarsamd64_arm64.bat -) else ( - echo ERROR: Please specify a target platform: win32, win64 or winarm64 - set ERRORLEVEL=1 - goto end -) - -:: Check if vcvars is already provided via the environment. -set vcvars="%CEF_VCVARS%" -if %vcvars% == "none" goto found_vcvars -if exist %vcvars% goto found_vcvars - -:: Search for the default VS installation path. -for %%x in (2022) do ( - for %%y in ("%PROGRAMFILES%" "%PROGRAMFILES(X86)%") do ( - for %%z in (Professional Enterprise Community BuildTools) do ( - set vcvars="%%~y\Microsoft Visual Studio\%%x\%%z\VC\Auxiliary\Build\%vcvarsbat%" - if exist !vcvars! goto found_vcvars - ) - ) -) - -echo ERROR: Failed to find vcvars -set ERRORLEVEL=1 -goto end - -:found_vcvars -echo vcvars: -echo %vcvars% - -if not %vcvars% == "none" ( - :: Set this variable to keep VS2017 < 15.5 from changing the current working directory. - set "VSCMD_START_DIR=%CD%" - call %vcvars% -) - -echo PATH: -echo %PATH% - -:: Remove the first argument and execute the command. -for /f "tokens=1,* delims= " %%a in ("%*") do set ALL_BUT_FIRST=%%b -echo command: -echo %ALL_BUT_FIRST% -%ALL_BUT_FIRST% - -:end -endlocal & set RC=%ERRORLEVEL% -goto omega - -:returncode -exit /B %RC% - -:omega -call :returncode %RC%