| // Copyright 2019 The PDFium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "testing/v8_initializer.h" |
| |
| #include <cstring> |
| |
| #include "public/fpdfview.h" |
| #include "testing/utils/file_util.h" |
| #include "testing/utils/path_service.h" |
| #include "third_party/base/numerics/safe_conversions.h" |
| #include "v8/include/libplatform/libplatform.h" |
| #include "v8/include/v8-initialization.h" |
| #include "v8/include/v8-snapshot.h" |
| |
| #ifdef PDF_ENABLE_XFA |
| #include "v8/include/cppgc/platform.h" |
| #endif |
| |
| namespace { |
| |
| #ifdef V8_USE_EXTERNAL_STARTUP_DATA |
| // Returns the full path for an external V8 data file based on either |
| // the currect exectuable path or an explicit override. |
| std::string GetFullPathForSnapshotFile(const std::string& exe_path, |
| const std::string& bin_dir, |
| const std::string& filename) { |
| std::string result; |
| if (!bin_dir.empty()) { |
| result = bin_dir; |
| if (*bin_dir.rbegin() != PATH_SEPARATOR) { |
| result += PATH_SEPARATOR; |
| } |
| } else if (!exe_path.empty()) { |
| size_t last_separator = exe_path.rfind(PATH_SEPARATOR); |
| if (last_separator != std::string::npos) { |
| result = exe_path.substr(0, last_separator + 1); |
| } |
| } |
| result += filename; |
| return result; |
| } |
| |
| bool GetExternalData(const std::string& exe_path, |
| const std::string& bin_dir, |
| const std::string& filename, |
| v8::StartupData* result_data) { |
| std::string full_path = |
| GetFullPathForSnapshotFile(exe_path, bin_dir, filename); |
| size_t data_length = 0; |
| std::unique_ptr<char, pdfium::FreeDeleter> data_buffer = |
| GetFileContents(full_path.c_str(), &data_length); |
| if (!data_buffer) |
| return false; |
| |
| result_data->data = data_buffer.release(); |
| result_data->raw_size = pdfium::base::checked_cast<int>(data_length); |
| return true; |
| } |
| #endif // V8_USE_EXTERNAL_STARTUP_DATA |
| |
| std::unique_ptr<v8::Platform> InitializeV8Common(const std::string& exe_path, |
| const std::string& js_flags) { |
| v8::V8::InitializeICUDefaultLocation(exe_path.c_str()); |
| |
| std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform(); |
| v8::V8::InitializePlatform(platform.get()); |
| #ifdef PDF_ENABLE_XFA |
| cppgc::InitializeProcess(platform->GetPageAllocator()); |
| #endif |
| |
| const char* recommended_v8_flags = FPDF_GetRecommendedV8Flags(); |
| v8::V8::SetFlagsFromString(recommended_v8_flags); |
| |
| if (!js_flags.empty()) |
| v8::V8::SetFlagsFromString(js_flags.c_str()); |
| |
| // By enabling predictable mode, V8 won't post any background tasks. |
| // By enabling GC, it makes it easier to chase use-after-free. |
| static const char kAdditionalV8Flags[] = "--predictable --expose-gc"; |
| v8::V8::SetFlagsFromString(kAdditionalV8Flags); |
| |
| v8::V8::Initialize(); |
| return platform; |
| } |
| |
| } // namespace |
| |
| #ifdef V8_USE_EXTERNAL_STARTUP_DATA |
| std::unique_ptr<v8::Platform> InitializeV8ForPDFiumWithStartupData( |
| const std::string& exe_path, |
| const std::string& js_flags, |
| const std::string& bin_dir, |
| v8::StartupData* snapshot_blob) { |
| std::unique_ptr<v8::Platform> platform = |
| InitializeV8Common(exe_path, js_flags); |
| if (snapshot_blob) { |
| if (!GetExternalData(exe_path, bin_dir, "snapshot_blob.bin", snapshot_blob)) |
| return nullptr; |
| v8::V8::SetSnapshotDataBlob(snapshot_blob); |
| } |
| return platform; |
| } |
| #else // V8_USE_EXTERNAL_STARTUP_DATA |
| std::unique_ptr<v8::Platform> InitializeV8ForPDFium( |
| const std::string& exe_path, |
| const std::string& js_flags) { |
| return InitializeV8Common(exe_path, js_flags); |
| } |
| #endif // V8_USE_EXTERNAL_STARTUP_DATA |
| |
| void ShutdownV8ForPDFium() { |
| #ifdef PDF_ENABLE_XFA |
| cppgc::ShutdownProcess(); |
| #endif |
| v8::V8::Dispose(); |
| v8::V8::DisposePlatform(); |
| } |