1 // Copyright 2019 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "testing/v8_initializer.h"
6
7 #include <stdlib.h>
8
9 #include <cstring>
10 #include <vector>
11
12 #include "core/fxcrt/fx_memcpy_wrappers.h"
13 #include "core/fxcrt/numerics/safe_conversions.h"
14 #include "public/fpdfview.h"
15 #include "testing/utils/file_util.h"
16 #include "testing/utils/path_service.h"
17 #include "v8/include/libplatform/libplatform.h"
18 #include "v8/include/v8-initialization.h"
19 #include "v8/include/v8-snapshot.h"
20
21 #ifdef PDF_ENABLE_XFA
22 #include "v8/include/cppgc/platform.h"
23 #endif
24
25 namespace {
26
27 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
28 // Returns the full path for an external V8 data file based on either
29 // the currect exectuable path or an explicit override.
GetFullPathForSnapshotFile(const std::string & exe_path,const std::string & bin_dir,const std::string & filename)30 std::string GetFullPathForSnapshotFile(const std::string& exe_path,
31 const std::string& bin_dir,
32 const std::string& filename) {
33 std::string result;
34 if (!bin_dir.empty()) {
35 result = bin_dir;
36 if (*bin_dir.rbegin() != PATH_SEPARATOR) {
37 result += PATH_SEPARATOR;
38 }
39 } else if (!exe_path.empty()) {
40 size_t last_separator = exe_path.rfind(PATH_SEPARATOR);
41 if (last_separator != std::string::npos) {
42 result = exe_path.substr(0, last_separator + 1);
43 }
44 }
45 result += filename;
46 return result;
47 }
48
GetExternalData(const std::string & exe_path,const std::string & bin_dir,const std::string & filename,v8::StartupData * result_data)49 bool GetExternalData(const std::string& exe_path,
50 const std::string& bin_dir,
51 const std::string& filename,
52 v8::StartupData* result_data) {
53 std::string full_path =
54 GetFullPathForSnapshotFile(exe_path, bin_dir, filename);
55 std::vector<uint8_t> data_buffer = GetFileContents(full_path.c_str());
56 if (data_buffer.empty()) {
57 return false;
58 }
59
60 // `result_data` takes ownership.
61 void* copy = malloc(data_buffer.size());
62 FXSYS_memcpy(copy, data_buffer.data(), data_buffer.size());
63 result_data->data = static_cast<char*>(copy);
64 result_data->raw_size = pdfium::checked_cast<int>(data_buffer.size());
65 return true;
66 }
67 #endif // V8_USE_EXTERNAL_STARTUP_DATA
68
InitializeV8Common(const std::string & exe_path,const std::string & js_flags)69 std::unique_ptr<v8::Platform> InitializeV8Common(const std::string& exe_path,
70 const std::string& js_flags) {
71 v8::V8::InitializeICUDefaultLocation(exe_path.c_str());
72
73 std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
74 v8::V8::InitializePlatform(platform.get());
75 #ifdef PDF_ENABLE_XFA
76 cppgc::InitializeProcess(platform->GetPageAllocator());
77 #endif
78
79 const char* recommended_v8_flags = FPDF_GetRecommendedV8Flags();
80 v8::V8::SetFlagsFromString(recommended_v8_flags);
81
82 if (!js_flags.empty())
83 v8::V8::SetFlagsFromString(js_flags.c_str());
84
85 // By enabling predictable mode, V8 won't post any background tasks.
86 // By enabling GC, it makes it easier to chase use-after-free.
87 static const char kAdditionalV8Flags[] = "--predictable --expose-gc";
88 v8::V8::SetFlagsFromString(kAdditionalV8Flags);
89
90 v8::V8::Initialize();
91 return platform;
92 }
93
94 } // namespace
95
96 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
InitializeV8ForPDFiumWithStartupData(const std::string & exe_path,const std::string & js_flags,const std::string & bin_dir,v8::StartupData * snapshot_blob)97 std::unique_ptr<v8::Platform> InitializeV8ForPDFiumWithStartupData(
98 const std::string& exe_path,
99 const std::string& js_flags,
100 const std::string& bin_dir,
101 v8::StartupData* snapshot_blob) {
102 std::unique_ptr<v8::Platform> platform =
103 InitializeV8Common(exe_path, js_flags);
104 if (snapshot_blob) {
105 if (!GetExternalData(exe_path, bin_dir, "snapshot_blob.bin", snapshot_blob))
106 return nullptr;
107 v8::V8::SetSnapshotDataBlob(snapshot_blob);
108 }
109 return platform;
110 }
111 #else // V8_USE_EXTERNAL_STARTUP_DATA
InitializeV8ForPDFium(const std::string & exe_path,const std::string & js_flags)112 std::unique_ptr<v8::Platform> InitializeV8ForPDFium(
113 const std::string& exe_path,
114 const std::string& js_flags) {
115 return InitializeV8Common(exe_path, js_flags);
116 }
117 #endif // V8_USE_EXTERNAL_STARTUP_DATA
118
ShutdownV8ForPDFium()119 void ShutdownV8ForPDFium() {
120 #ifdef PDF_ENABLE_XFA
121 cppgc::ShutdownProcess();
122 #endif
123 v8::V8::Dispose();
124 v8::V8::DisposePlatform();
125 }
126