xref: /aosp_15_r20/external/pdfium/testing/v8_initializer.cpp (revision 3ac0a46f773bac49fa9476ec2b1cf3f8da5ec3a4)
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