1 // Copyright 2019 PDFium Authors. All rights reserved.
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 "v8/include/libplatform/libplatform.h"
13 #include "v8/include/v8.h"
14 
15 namespace {
16 
17 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
18 // Returns the full path for an external V8 data file based on either
19 // the currect exectuable path or an explicit override.
GetFullPathForSnapshotFile(const std::string & exe_path,const std::string & bin_dir,const std::string & filename)20 std::string GetFullPathForSnapshotFile(const std::string& exe_path,
21                                        const std::string& bin_dir,
22                                        const std::string& filename) {
23   std::string result;
24   if (!bin_dir.empty()) {
25     result = bin_dir;
26     if (*bin_dir.rbegin() != PATH_SEPARATOR) {
27       result += PATH_SEPARATOR;
28     }
29   } else if (!exe_path.empty()) {
30     size_t last_separator = exe_path.rfind(PATH_SEPARATOR);
31     if (last_separator != std::string::npos) {
32       result = exe_path.substr(0, last_separator + 1);
33     }
34   }
35   result += filename;
36   return result;
37 }
38 
GetExternalData(const std::string & exe_path,const std::string & bin_dir,const std::string & filename,v8::StartupData * result_data)39 bool GetExternalData(const std::string& exe_path,
40                      const std::string& bin_dir,
41                      const std::string& filename,
42                      v8::StartupData* result_data) {
43   std::string full_path =
44       GetFullPathForSnapshotFile(exe_path, bin_dir, filename);
45   size_t data_length = 0;
46   std::unique_ptr<char, pdfium::FreeDeleter> data_buffer =
47       GetFileContents(full_path.c_str(), &data_length);
48   if (!data_buffer)
49     return false;
50 
51   result_data->data = data_buffer.release();
52   result_data->raw_size = data_length;
53   return true;
54 }
55 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
56 
InitializeV8Common(const std::string & exe_path)57 std::unique_ptr<v8::Platform> InitializeV8Common(const std::string& exe_path) {
58   v8::V8::InitializeICUDefaultLocation(exe_path.c_str());
59 
60   std::unique_ptr<v8::Platform> platform = v8::platform::NewDefaultPlatform();
61   v8::V8::InitializePlatform(platform.get());
62 
63   const char* recommended_v8_flags = FPDF_GetRecommendedV8Flags();
64   v8::V8::SetFlagsFromString(recommended_v8_flags);
65 
66   // By enabling predictable mode, V8 won't post any background tasks.
67   // By enabling GC, it makes it easier to chase use-after-free.
68   static const char kAdditionalV8Flags[] = "--predictable --expose-gc";
69   v8::V8::SetFlagsFromString(kAdditionalV8Flags);
70 
71   v8::V8::Initialize();
72   return platform;
73 }
74 
75 }  // namespace
76 
77 #ifdef V8_USE_EXTERNAL_STARTUP_DATA
InitializeV8ForPDFiumWithStartupData(const std::string & exe_path,const std::string & bin_dir,v8::StartupData * snapshot_blob)78 std::unique_ptr<v8::Platform> InitializeV8ForPDFiumWithStartupData(
79     const std::string& exe_path,
80     const std::string& bin_dir,
81     v8::StartupData* snapshot_blob) {
82   std::unique_ptr<v8::Platform> platform = InitializeV8Common(exe_path);
83   if (snapshot_blob) {
84     if (!GetExternalData(exe_path, bin_dir, "snapshot_blob.bin", snapshot_blob))
85       return nullptr;
86     v8::V8::SetSnapshotDataBlob(snapshot_blob);
87   }
88   return platform;
89 }
90 #else   // V8_USE_EXTERNAL_STARTUP_DATA
InitializeV8ForPDFium(const std::string & exe_path)91 std::unique_ptr<v8::Platform> InitializeV8ForPDFium(
92     const std::string& exe_path) {
93   return InitializeV8Common(exe_path);
94 }
95 #endif  // V8_USE_EXTERNAL_STARTUP_DATA
96