• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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