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