1 // Copyright 2012 the V8 project 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 #ifndef V8_D8_D8_H_
6 #define V8_D8_D8_H_
7 
8 #include <iterator>
9 #include <map>
10 #include <memory>
11 #include <queue>
12 #include <string>
13 #include <unordered_map>
14 #include <unordered_set>
15 #include <vector>
16 
17 #include "include/v8-array-buffer.h"
18 #include "include/v8-isolate.h"
19 #include "include/v8-script.h"
20 #include "src/base/once.h"
21 #include "src/base/platform/time.h"
22 #include "src/base/platform/wrappers.h"
23 #include "src/d8/async-hooks-wrapper.h"
24 #include "src/strings/string-hasher.h"
25 #include "src/utils/allocation.h"
26 #include "src/utils/utils.h"
27 
28 namespace v8 {
29 
30 class BackingStore;
31 class CompiledWasmModule;
32 class D8Console;
33 class Message;
34 class TryCatch;
35 
36 enum class ModuleType { kJavaScript, kJSON, kInvalid };
37 
38 namespace internal {
39 class CancelableTaskManager;
40 }  // namespace internal
41 
42 struct DynamicImportData;
43 
44 // A single counter in a counter collection.
45 class Counter {
46  public:
47   static const int kMaxNameSize = 64;
48   int32_t* Bind(const char* name, bool histogram);
ptr()49   int32_t* ptr() { return &count_; }
count()50   int32_t count() { return count_; }
sample_total()51   int32_t sample_total() { return sample_total_; }
is_histogram()52   bool is_histogram() { return is_histogram_; }
53   void AddSample(int32_t sample);
54 
55  private:
56   int32_t count_;
57   int32_t sample_total_;
58   bool is_histogram_;
59   uint8_t name_[kMaxNameSize];
60 };
61 
62 // A set of counters and associated information.  An instance of this
63 // class is stored directly in the memory-mapped counters file if
64 // the --map-counters options is used
65 class CounterCollection {
66  public:
67   CounterCollection();
68   Counter* GetNextCounter();
69 
70  private:
71   static const unsigned kMaxCounters = 512;
72   uint32_t magic_number_;
73   uint32_t max_counters_;
74   uint32_t max_name_size_;
75   uint32_t counters_in_use_;
76   Counter counters_[kMaxCounters];
77 };
78 
79 using CounterMap = std::unordered_map<std::string, Counter*>;
80 
81 class SourceGroup {
82  public:
SourceGroup()83   SourceGroup()
84       : next_semaphore_(0),
85         done_semaphore_(0),
86         thread_(nullptr),
87         argv_(nullptr),
88         begin_offset_(0),
89         end_offset_(0) {}
90 
91   ~SourceGroup();
92 
Begin(char ** argv,int offset)93   void Begin(char** argv, int offset) {
94     argv_ = const_cast<const char**>(argv);
95     begin_offset_ = offset;
96   }
97 
End(int offset)98   void End(int offset) { end_offset_ = offset; }
99 
100   // Returns true on success, false if an uncaught exception was thrown.
101   bool Execute(Isolate* isolate);
102 
103   void StartExecuteInThread();
104   void WaitForThread();
105   void JoinThread();
106 
107  private:
108   class IsolateThread : public base::Thread {
109    public:
110     explicit IsolateThread(SourceGroup* group);
111 
Run()112     void Run() override { group_->ExecuteInThread(); }
113 
114    private:
115     SourceGroup* group_;
116   };
117 
118   void ExecuteInThread();
119 
120   base::Semaphore next_semaphore_;
121   base::Semaphore done_semaphore_;
122   base::Thread* thread_;
123 
124   void ExitShell(int exit_code);
125 
126   const char** argv_;
127   int begin_offset_;
128   int end_offset_;
129 };
130 
131 class SerializationData {
132  public:
133   SerializationData() = default;
134   SerializationData(const SerializationData&) = delete;
135   SerializationData& operator=(const SerializationData&) = delete;
136 
data()137   uint8_t* data() { return data_.get(); }
size()138   size_t size() { return size_; }
backing_stores()139   const std::vector<std::shared_ptr<v8::BackingStore>>& backing_stores() {
140     return backing_stores_;
141   }
sab_backing_stores()142   const std::vector<std::shared_ptr<v8::BackingStore>>& sab_backing_stores() {
143     return sab_backing_stores_;
144   }
compiled_wasm_modules()145   const std::vector<CompiledWasmModule>& compiled_wasm_modules() {
146     return compiled_wasm_modules_;
147   }
148 
149  private:
150   struct DataDeleter {
operatorDataDeleter151     void operator()(uint8_t* p) const { base::Free(p); }
152   };
153 
154   std::unique_ptr<uint8_t, DataDeleter> data_;
155   size_t size_ = 0;
156   std::vector<std::shared_ptr<v8::BackingStore>> backing_stores_;
157   std::vector<std::shared_ptr<v8::BackingStore>> sab_backing_stores_;
158   std::vector<CompiledWasmModule> compiled_wasm_modules_;
159 
160  private:
161   friend class Serializer;
162 };
163 
164 class SerializationDataQueue {
165  public:
166   void Enqueue(std::unique_ptr<SerializationData> data);
167   bool Dequeue(std::unique_ptr<SerializationData>* data);
168   bool IsEmpty();
169   void Clear();
170 
171  private:
172   base::Mutex mutex_;
173   std::vector<std::unique_ptr<SerializationData>> data_;
174 };
175 
176 class Worker : public std::enable_shared_from_this<Worker> {
177  public:
178   explicit Worker(const char* script);
179   ~Worker();
180 
181   // Post a message to the worker. The worker will take ownership of the
182   // SerializationData. This function should only be called by the thread that
183   // created the Worker.
184   void PostMessage(std::unique_ptr<SerializationData> data);
185   // Synchronously retrieve messages from the worker's outgoing message queue.
186   // If there is no message in the queue, block until a message is available.
187   // If there are no messages in the queue and the worker is no longer running,
188   // return nullptr.
189   // This function should only be called by the thread that created the Worker.
190   std::unique_ptr<SerializationData> GetMessage();
191   // Terminate the worker's event loop. Messages from the worker that have been
192   // queued can still be read via GetMessage().
193   // This function can be called by any thread.
194   void Terminate();
195   // Terminate and join the thread.
196   // This function can be called by any thread.
197   void TerminateAndWaitForThread();
198 
199   // Start running the given worker in another thread.
200   static bool StartWorkerThread(std::shared_ptr<Worker> worker);
201 
202  private:
203   friend class ProcessMessageTask;
204   friend class TerminateTask;
205 
206   void ProcessMessage(std::unique_ptr<SerializationData> data);
207   void ProcessMessages();
208 
209   class WorkerThread : public base::Thread {
210    public:
WorkerThread(std::shared_ptr<Worker> worker)211     explicit WorkerThread(std::shared_ptr<Worker> worker)
212         : base::Thread(base::Thread::Options("WorkerThread")),
213           worker_(std::move(worker)) {}
214 
215     void Run() override;
216 
217    private:
218     std::shared_ptr<Worker> worker_;
219   };
220 
221   void ExecuteInThread();
222   static void PostMessageOut(const v8::FunctionCallbackInfo<v8::Value>& args);
223 
224   base::Semaphore out_semaphore_{0};
225   SerializationDataQueue out_queue_;
226   base::Thread* thread_ = nullptr;
227   char* script_;
228   std::atomic<bool> running_;
229   // For signalling that the worker has started.
230   base::Semaphore started_semaphore_{0};
231 
232   // For posting tasks to the worker
233   std::shared_ptr<TaskRunner> task_runner_;
234   i::CancelableTaskManager* task_manager_;
235 
236   // Protects reading / writing task_runner_. (The TaskRunner itself doesn't
237   // need locking, but accessing the Worker's data member does.)
238   base::Mutex worker_mutex_;
239 
240   // Only accessed by the worker thread.
241   Isolate* isolate_ = nullptr;
242   v8::Persistent<v8::Context> context_;
243 };
244 
245 class PerIsolateData {
246  public:
247   explicit PerIsolateData(Isolate* isolate);
248 
249   ~PerIsolateData();
250 
Get(Isolate * isolate)251   inline static PerIsolateData* Get(Isolate* isolate) {
252     return reinterpret_cast<PerIsolateData*>(isolate->GetData(0));
253   }
254 
255   class V8_NODISCARD RealmScope {
256    public:
257     explicit RealmScope(PerIsolateData* data);
258     ~RealmScope();
259 
260    private:
261     PerIsolateData* data_;
262   };
263 
264   // Contrary to RealmScope (which creates a new Realm), ExplicitRealmScope
265   // allows for entering an existing Realm, as specified by its index.
266   class V8_NODISCARD ExplicitRealmScope {
267    public:
268     explicit ExplicitRealmScope(PerIsolateData* data, int index);
269     ~ExplicitRealmScope();
270 
271     Local<Context> context() const;
272 
273    private:
274     PerIsolateData* data_;
275     Local<Context> realm_;
276     int index_;
277     int previous_index_;
278   };
279 
280   inline void SetTimeout(Local<Function> callback, Local<Context> context);
281   inline MaybeLocal<Function> GetTimeoutCallback();
282   inline MaybeLocal<Context> GetTimeoutContext();
283 
GetAsyncHooks()284   AsyncHooks* GetAsyncHooks() { return async_hooks_wrapper_; }
285 
286   void RemoveUnhandledPromise(Local<Promise> promise);
287   void AddUnhandledPromise(Local<Promise> promise, Local<Message> message,
288                            Local<Value> exception);
289   int HandleUnhandledPromiseRejections();
290 
291   // Keep track of DynamicImportData so we can properly free it on shutdown
292   // when LEAK_SANITIZER is active.
293   void AddDynamicImportData(DynamicImportData*);
294   void DeleteDynamicImportData(DynamicImportData*);
295 
296   Local<FunctionTemplate> GetTestApiObjectCtor() const;
297   void SetTestApiObjectCtor(Local<FunctionTemplate> ctor);
298 
299   Local<FunctionTemplate> GetSnapshotObjectCtor() const;
300   void SetSnapshotObjectCtor(Local<FunctionTemplate> ctor);
301 
302  private:
303   friend class Shell;
304   friend class RealmScope;
305   Isolate* isolate_;
306   int realm_count_;
307   int realm_current_;
308   int realm_switch_;
309   Global<Context>* realms_;
310   Global<Value> realm_shared_;
311   std::queue<Global<Function>> set_timeout_callbacks_;
312   std::queue<Global<Context>> set_timeout_contexts_;
313   bool ignore_unhandled_promises_;
314   std::vector<std::tuple<Global<Promise>, Global<Message>, Global<Value>>>
315       unhandled_promises_;
316   AsyncHooks* async_hooks_wrapper_;
317 #if defined(LEAK_SANITIZER)
318   std::unordered_set<DynamicImportData*> import_data_;
319 #endif
320   Global<FunctionTemplate> test_api_object_ctor_;
321   Global<FunctionTemplate> snapshot_object_ctor_;
322 
323   int RealmIndexOrThrow(const v8::FunctionCallbackInfo<v8::Value>& args,
324                         int arg_offset);
325   int RealmFind(Local<Context> context);
326 };
327 
328 extern bool check_d8_flag_contradictions;
329 
330 class ShellOptions {
331  public:
332   enum CodeCacheOptions {
333     kNoProduceCache,
334     kProduceCache,
335     kProduceCacheAfterExecute
336   };
337 
~ShellOptions()338   ~ShellOptions() { delete[] isolate_sources; }
339 
340   // In analogy to Flag::CheckFlagChange() in src/flags/flag.cc, only allow
341   // repeated flags for identical boolean values. We allow exceptions for flags
342   // with enum-like arguments since their conflicts can also be specified
343   // completely.
344   template <class T,
345             bool kAllowIdenticalAssignment = std::is_same<T, bool>::value>
346   class DisallowReassignment {
347    public:
DisallowReassignment(const char * name,T value)348     DisallowReassignment(const char* name, T value)
349         : name_(name), value_(value) {}
350 
T()351     operator T() const { return value_; }
get()352     T get() const { return value_; }
353     DisallowReassignment& operator=(T value) {
354       if (check_d8_flag_contradictions) {
355         if (kAllowIdenticalAssignment) {
356           if (specified_ && value_ != value) {
357             FATAL("Contradictory values for d8 flag --%s", name_);
358           }
359         } else {
360           if (specified_) {
361             FATAL("Repeated specification of d8 flag --%s", name_);
362           }
363         }
364       }
365       value_ = value;
366       specified_ = true;
367       return *this;
368     }
Overwrite(T value)369     void Overwrite(T value) { value_ = value; }
370 
371    private:
372     const char* name_;
373     T value_;
374     bool specified_ = false;
375   };
376 
377   DisallowReassignment<const char*> d8_path = {"d8-path", ""};
378   DisallowReassignment<bool> fuzzilli_coverage_statistics = {
379       "fuzzilli-coverage-statistics", false};
380   DisallowReassignment<bool> fuzzilli_enable_builtins_coverage = {
381       "fuzzilli-enable-builtins-coverage", true};
382   DisallowReassignment<bool> send_idle_notification = {"send-idle-notification",
383                                                        false};
384   DisallowReassignment<bool> invoke_weak_callbacks = {"invoke-weak-callbacks",
385                                                       false};
386   DisallowReassignment<bool> omit_quit = {"omit-quit", false};
387   DisallowReassignment<bool> wait_for_background_tasks = {
388       "wait-for-background-tasks", true};
389   DisallowReassignment<bool> simulate_errors = {"simulate-errors", false};
390   DisallowReassignment<bool> stress_opt = {"stress-opt", false};
391   DisallowReassignment<int> stress_runs = {"stress-runs", 1};
392   DisallowReassignment<bool> interactive_shell = {"shell", false};
393   bool test_shell = false;
394   DisallowReassignment<bool> expected_to_throw = {"throws", false};
395   DisallowReassignment<bool> no_fail = {"no-fail", false};
396   DisallowReassignment<bool> ignore_unhandled_promises = {
397       "ignore-unhandled-promises", false};
398   DisallowReassignment<bool> mock_arraybuffer_allocator = {
399       "mock-arraybuffer-allocator", false};
400   DisallowReassignment<size_t> mock_arraybuffer_allocator_limit = {
401       "mock-arraybuffer-allocator-limit", 0};
402 #if MULTI_MAPPED_ALLOCATOR_AVAILABLE
403   DisallowReassignment<bool> multi_mapped_mock_allocator = {
404       "multi-mapped-mock-allocator", false};
405 #endif
406   DisallowReassignment<bool> enable_inspector = {"enable-inspector", false};
407   int num_isolates = 1;
408   DisallowReassignment<v8::ScriptCompiler::CompileOptions, true>
409       compile_options = {"cache", v8::ScriptCompiler::kNoCompileOptions};
410   DisallowReassignment<CodeCacheOptions, true> code_cache_options = {
411       "cache", CodeCacheOptions::kNoProduceCache};
412   DisallowReassignment<bool> streaming_compile = {"streaming-compile", false};
413   DisallowReassignment<SourceGroup*> isolate_sources = {"isolate-sources",
414                                                         nullptr};
415   DisallowReassignment<const char*> icu_data_file = {"icu-data-file", nullptr};
416   DisallowReassignment<const char*> icu_locale = {"icu-locale", nullptr};
417   DisallowReassignment<const char*> snapshot_blob = {"snapshot_blob", nullptr};
418   DisallowReassignment<bool> trace_enabled = {"trace-enabled", false};
419   DisallowReassignment<const char*> trace_path = {"trace-path", nullptr};
420   DisallowReassignment<const char*> trace_config = {"trace-config", nullptr};
421   DisallowReassignment<const char*> lcov_file = {"lcov", nullptr};
422   DisallowReassignment<bool> disable_in_process_stack_traces = {
423       "disable-in-process-stack-traces", false};
424   DisallowReassignment<int> read_from_tcp_port = {"read-from-tcp-port", -1};
425   DisallowReassignment<bool> enable_os_system = {"enable-os-system", false};
426   DisallowReassignment<bool> quiet_load = {"quiet-load", false};
427   DisallowReassignment<int> thread_pool_size = {"thread-pool-size", 0};
428   DisallowReassignment<bool> stress_delay_tasks = {"stress-delay-tasks", false};
429   std::vector<const char*> arguments;
430   DisallowReassignment<bool> include_arguments = {"arguments", true};
431   DisallowReassignment<bool> cpu_profiler = {"cpu-profiler", false};
432   DisallowReassignment<bool> cpu_profiler_print = {"cpu-profiler-print", false};
433   DisallowReassignment<bool> fuzzy_module_file_extensions = {
434       "fuzzy-module-file-extensions", true};
435   DisallowReassignment<bool> enable_system_instrumentation = {
436       "enable-system-instrumentation", false};
437   DisallowReassignment<const char*> web_snapshot_config = {
438       "web-snapshot-config", nullptr};
439   DisallowReassignment<bool> d8_web_snapshot_api = {
440       "experimental-d8-web-snapshot-api", false};
441   DisallowReassignment<bool> compile_only = {"compile-only", false};
442   DisallowReassignment<int> repeat_compile = {"repeat-compile", 1};
443 #if V8_ENABLE_WEBASSEMBLY
444   DisallowReassignment<bool> wasm_trap_handler = {"wasm-trap-handler", true};
445 #endif  // V8_ENABLE_WEBASSEMBLY
446   DisallowReassignment<bool> expose_fast_api = {"expose-fast-api", false};
447 };
448 
449 class Shell : public i::AllStatic {
450  public:
451   enum PrintResult : bool { kPrintResult = true, kNoPrintResult = false };
452   enum ReportExceptions : bool {
453     kReportExceptions = true,
454     kNoReportExceptions = false
455   };
456   enum ProcessMessageQueue : bool {
457     kProcessMessageQueue = true,
458     kNoProcessMessageQueue = false
459   };
460   enum class CodeType { kFileName, kString, kFunction, kInvalid, kNone };
461 
462   static bool ExecuteString(Isolate* isolate, Local<String> source,
463                             Local<Value> name, PrintResult print_result,
464                             ReportExceptions report_exceptions,
465                             ProcessMessageQueue process_message_queue);
466   static bool ExecuteModule(Isolate* isolate, const char* file_name);
467   static bool ExecuteWebSnapshot(Isolate* isolate, const char* file_name);
468   static void ReportException(Isolate* isolate, Local<Message> message,
469                               Local<Value> exception);
470   static void ReportException(Isolate* isolate, TryCatch* try_catch);
471   static Local<String> ReadFile(Isolate* isolate, const char* name,
472                                 bool should_throw = true);
473   static Local<String> WasmLoadSourceMapCallback(Isolate* isolate,
474                                                  const char* name);
475   static Local<Context> CreateEvaluationContext(Isolate* isolate);
476   static int RunMain(Isolate* isolate, bool last_run);
477   static int Main(int argc, char* argv[]);
478   static void Exit(int exit_code);
479   static void OnExit(Isolate* isolate);
480   static void CollectGarbage(Isolate* isolate);
481   static bool EmptyMessageQueues(Isolate* isolate);
482   static bool CompleteMessageLoop(Isolate* isolate);
483 
484   static bool HandleUnhandledPromiseRejections(Isolate* isolate);
485 
486   static void PostForegroundTask(Isolate* isolate, std::unique_ptr<Task> task);
487   static void PostBlockingBackgroundTask(std::unique_ptr<Task> task);
488 
489   static std::unique_ptr<SerializationData> SerializeValue(
490       Isolate* isolate, Local<Value> value, Local<Value> transfer);
491   static MaybeLocal<Value> DeserializeValue(
492       Isolate* isolate, std::unique_ptr<SerializationData> data);
493   static int* LookupCounter(const char* name);
494   static void* CreateHistogram(const char* name, int min, int max,
495                                size_t buckets);
496   static void AddHistogramSample(void* histogram, int sample);
497   static void MapCounters(v8::Isolate* isolate, const char* name);
498 
499   static void PerformanceNow(const v8::FunctionCallbackInfo<v8::Value>& args);
500   static void PerformanceMeasureMemory(
501       const v8::FunctionCallbackInfo<v8::Value>& args);
502 
503   static void RealmCurrent(const v8::FunctionCallbackInfo<v8::Value>& args);
504   static void RealmOwner(const v8::FunctionCallbackInfo<v8::Value>& args);
505   static void RealmGlobal(const v8::FunctionCallbackInfo<v8::Value>& args);
506   static void RealmCreate(const v8::FunctionCallbackInfo<v8::Value>& args);
507   static void RealmNavigate(const v8::FunctionCallbackInfo<v8::Value>& args);
508   static void RealmCreateAllowCrossRealmAccess(
509       const v8::FunctionCallbackInfo<v8::Value>& args);
510   static void RealmDetachGlobal(
511       const v8::FunctionCallbackInfo<v8::Value>& args);
512   static void RealmDispose(const v8::FunctionCallbackInfo<v8::Value>& args);
513   static void RealmSwitch(const v8::FunctionCallbackInfo<v8::Value>& args);
514   static void RealmEval(const v8::FunctionCallbackInfo<v8::Value>& args);
515   static void RealmSharedGet(Local<String> property,
516                              const PropertyCallbackInfo<Value>& info);
517   static void RealmSharedSet(Local<String> property, Local<Value> value,
518                              const PropertyCallbackInfo<void>& info);
519   static void RealmTakeWebSnapshot(
520       const v8::FunctionCallbackInfo<v8::Value>& args);
521   static void RealmUseWebSnapshot(
522       const v8::FunctionCallbackInfo<v8::Value>& args);
523 
524   static void LogGetAndStop(const v8::FunctionCallbackInfo<v8::Value>& args);
525   static void TestVerifySourcePositions(
526       const v8::FunctionCallbackInfo<v8::Value>& args);
527 
528   static void AsyncHooksCreateHook(
529       const v8::FunctionCallbackInfo<v8::Value>& args);
530   static void AsyncHooksExecutionAsyncId(
531       const v8::FunctionCallbackInfo<v8::Value>& args);
532   static void AsyncHooksTriggerAsyncId(
533       const v8::FunctionCallbackInfo<v8::Value>& args);
534 
535   static void SetPromiseHooks(const v8::FunctionCallbackInfo<v8::Value>& args);
536 
537   static void Print(const v8::FunctionCallbackInfo<v8::Value>& args);
538   static void PrintErr(const v8::FunctionCallbackInfo<v8::Value>& args);
539   static void WriteStdout(const v8::FunctionCallbackInfo<v8::Value>& args);
540   static void WaitUntilDone(const v8::FunctionCallbackInfo<v8::Value>& args);
541   static void NotifyDone(const v8::FunctionCallbackInfo<v8::Value>& args);
542   static void QuitOnce(v8::FunctionCallbackInfo<v8::Value>* args);
543   static void Quit(const v8::FunctionCallbackInfo<v8::Value>& args);
544   static void Version(const v8::FunctionCallbackInfo<v8::Value>& args);
545   static void ReadFile(const v8::FunctionCallbackInfo<v8::Value>& args);
546   static char* ReadChars(const char* name, int* size_out);
547   static MaybeLocal<PrimitiveArray> ReadLines(Isolate* isolate,
548                                               const char* name);
549   static void ReadBuffer(const v8::FunctionCallbackInfo<v8::Value>& args);
550   static Local<String> ReadFromStdin(Isolate* isolate);
ReadLine(const v8::FunctionCallbackInfo<v8::Value> & args)551   static void ReadLine(const v8::FunctionCallbackInfo<v8::Value>& args) {
552     args.GetReturnValue().Set(ReadFromStdin(args.GetIsolate()));
553   }
554   static void WriteChars(const char* name, uint8_t* buffer, size_t buffer_size);
555   static void ExecuteFile(const v8::FunctionCallbackInfo<v8::Value>& args);
556   static void SetTimeout(const v8::FunctionCallbackInfo<v8::Value>& args);
557   static void ReadCodeTypeAndArguments(
558       const v8::FunctionCallbackInfo<v8::Value>& args, int index,
559       CodeType* code_type, Local<Value>* arguments = nullptr);
560   static bool FunctionAndArgumentsToString(Local<Function> function,
561                                            Local<Value> arguments,
562                                            Local<String>* source,
563                                            Isolate* isolate);
564   static MaybeLocal<String> ReadSource(
565       const v8::FunctionCallbackInfo<v8::Value>& args, int index,
566       CodeType default_type);
567   static void WorkerNew(const v8::FunctionCallbackInfo<v8::Value>& args);
568   static void WorkerPostMessage(
569       const v8::FunctionCallbackInfo<v8::Value>& args);
570   static void WorkerGetMessage(const v8::FunctionCallbackInfo<v8::Value>& args);
571   static void WorkerTerminate(const v8::FunctionCallbackInfo<v8::Value>& args);
572   static void WorkerTerminateAndWait(
573       const v8::FunctionCallbackInfo<v8::Value>& args);
574   // The OS object on the global object contains methods for performing
575   // operating system calls:
576   //
577   // os.system("program_name", ["arg1", "arg2", ...], timeout1, timeout2) will
578   // run the command, passing the arguments to the program.  The standard output
579   // of the program will be picked up and returned as a multiline string.  If
580   // timeout1 is present then it should be a number.  -1 indicates no timeout
581   // and a positive number is used as a timeout in milliseconds that limits the
582   // time spent waiting between receiving output characters from the program.
583   // timeout2, if present, should be a number indicating the limit in
584   // milliseconds on the total running time of the program.  Exceptions are
585   // thrown on timeouts or other errors or if the exit status of the program
586   // indicates an error.
587   static void System(const v8::FunctionCallbackInfo<v8::Value>& args);
588 
589   // os.chdir(dir) changes directory to the given directory.  Throws an
590   // exception/ on error.
591   static void ChangeDirectory(const v8::FunctionCallbackInfo<v8::Value>& args);
592 
593   // os.setenv(variable, value) sets an environment variable.  Repeated calls to
594   // this method leak memory due to the API of setenv in the standard C library.
595   static void SetEnvironment(const v8::FunctionCallbackInfo<v8::Value>& args);
596   static void UnsetEnvironment(const v8::FunctionCallbackInfo<v8::Value>& args);
597 
598   // os.umask(alue) calls the umask system call and returns the old umask.
599   static void SetUMask(const v8::FunctionCallbackInfo<v8::Value>& args);
600 
601   // os.mkdirp(name, mask) creates a directory.  The mask (if present) is anded
602   // with the current umask.  Intermediate directories are created if necessary.
603   // An exception is not thrown if the directory already exists.  Analogous to
604   // the "mkdir -p" command.
605   static void MakeDirectory(const v8::FunctionCallbackInfo<v8::Value>& args);
606   static void RemoveDirectory(const v8::FunctionCallbackInfo<v8::Value>& args);
607   static MaybeLocal<Promise> HostImportModuleDynamically(
608       Local<Context> context, Local<ScriptOrModule> referrer,
609       Local<String> specifier, Local<FixedArray> import_assertions);
610 
611   static void ModuleResolutionSuccessCallback(
612       const v8::FunctionCallbackInfo<v8::Value>& info);
613   static void ModuleResolutionFailureCallback(
614       const v8::FunctionCallbackInfo<v8::Value>& info);
615   static void HostInitializeImportMetaObject(Local<Context> context,
616                                              Local<Module> module,
617                                              Local<Object> meta);
618 
619 #ifdef V8_FUZZILLI
620   static void Fuzzilli(const v8::FunctionCallbackInfo<v8::Value>& args);
621 #endif  // V8_FUZZILLI
622 
623   // Data is of type DynamicImportData*. We use void* here to be able
624   // to conform with MicrotaskCallback interface and enqueue this
625   // function in the microtask queue.
626   static void DoHostImportModuleDynamically(void* data);
627   static void AddOSMethods(v8::Isolate* isolate,
628                            Local<ObjectTemplate> os_template);
629 
630   static const char* kPrompt;
631   static ShellOptions options;
632   static ArrayBuffer::Allocator* array_buffer_allocator;
633 
634   static void SetWaitUntilDone(Isolate* isolate, bool value);
635   static void NotifyStartStreamingTask(Isolate* isolate);
636   static void NotifyFinishStreamingTask(Isolate* isolate);
637 
638   static char* ReadCharsFromTcpPort(const char* name, int* size_out);
639 
set_script_executed()640   static void set_script_executed() { script_executed_.store(true); }
use_interactive_shell()641   static bool use_interactive_shell() {
642     return (options.interactive_shell || !script_executed_.load()) &&
643            !options.test_shell;
644   }
645 
update_script_size(int size)646   static void update_script_size(int size) {
647     if (size > 0) valid_fuzz_script_.store(true);
648   }
is_valid_fuzz_script()649   static bool is_valid_fuzz_script() { return valid_fuzz_script_.load(); }
650 
651   static void WaitForRunningWorkers();
652   static void AddRunningWorker(std::shared_ptr<Worker> worker);
653   static void RemoveRunningWorker(const std::shared_ptr<Worker>& worker);
654 
655   static void Initialize(Isolate* isolate, D8Console* console,
656                          bool isOnMainThread = true);
657 
658   static void PromiseRejectCallback(v8::PromiseRejectMessage reject_message);
659 
660   static Local<FunctionTemplate> CreateSnapshotTemplate(Isolate* isolate);
661 
662  private:
663   static Global<Context> evaluation_context_;
664   static base::OnceType quit_once_;
665   static Global<Function> stringify_function_;
666   static const char* stringify_source_;
667   static CounterMap* counter_map_;
668   // We statically allocate a set of local counters to be used if we
669   // don't want to store the stats in a memory-mapped file
670   static CounterCollection local_counters_;
671   static CounterCollection* counters_;
672   static base::OS::MemoryMappedFile* counters_file_;
673   static base::LazyMutex context_mutex_;
674   static const base::TimeTicks kInitialTicks;
675 
676   static base::LazyMutex workers_mutex_;  // Guards the following members.
677   static bool allow_new_workers_;
678   static std::unordered_set<std::shared_ptr<Worker>> running_workers_;
679 
680   // Multiple isolates may update these flags concurrently.
681   static std::atomic<bool> script_executed_;
682   static std::atomic<bool> valid_fuzz_script_;
683 
684   static void WriteIgnitionDispatchCountersFile(v8::Isolate* isolate);
685   // Append LCOV coverage data to file.
686   static void WriteLcovData(v8::Isolate* isolate, const char* file);
687   static Counter* GetCounter(const char* name, bool is_histogram);
688   static Local<String> Stringify(Isolate* isolate, Local<Value> value);
689   static void RunShell(Isolate* isolate);
690   static bool SetOptions(int argc, char* argv[]);
691 
692   static void NodeTypeCallback(const v8::FunctionCallbackInfo<v8::Value>& args);
693 
694   static Local<FunctionTemplate> CreateNodeTemplates(Isolate* isolate);
695   static Local<ObjectTemplate> CreateGlobalTemplate(Isolate* isolate);
696   static Local<ObjectTemplate> CreateOSTemplate(Isolate* isolate);
697   static Local<FunctionTemplate> CreateWorkerTemplate(Isolate* isolate);
698   static Local<ObjectTemplate> CreateAsyncHookTemplate(Isolate* isolate);
699   static Local<ObjectTemplate> CreateTestRunnerTemplate(Isolate* isolate);
700   static Local<ObjectTemplate> CreatePerformanceTemplate(Isolate* isolate);
701   static Local<ObjectTemplate> CreateRealmTemplate(Isolate* isolate);
702   static Local<ObjectTemplate> CreateD8Template(Isolate* isolate);
703   static Local<FunctionTemplate> CreateTestFastCApiTemplate(Isolate* isolate);
704   static Local<FunctionTemplate> CreateLeafInterfaceTypeTemplate(
705       Isolate* isolate);
706 
707   static MaybeLocal<Context> CreateRealm(
708       const v8::FunctionCallbackInfo<v8::Value>& args, int index,
709       v8::MaybeLocal<Value> global_object);
710   static void DisposeRealm(const v8::FunctionCallbackInfo<v8::Value>& args,
711                            int index);
712   static MaybeLocal<Module> FetchModuleTree(v8::Local<v8::Module> origin_module,
713                                             v8::Local<v8::Context> context,
714                                             const std::string& file_name,
715                                             ModuleType module_type);
716 
717   static MaybeLocal<Value> JSONModuleEvaluationSteps(Local<Context> context,
718                                                      Local<Module> module);
719 
720   template <class T>
721   static MaybeLocal<T> CompileString(Isolate* isolate, Local<Context> context,
722                                      Local<String> source,
723                                      const ScriptOrigin& origin);
724 
725   static ScriptCompiler::CachedData* LookupCodeCache(Isolate* isolate,
726                                                      Local<Value> name);
727   static void StoreInCodeCache(Isolate* isolate, Local<Value> name,
728                                const ScriptCompiler::CachedData* data);
729   // We may have multiple isolates running concurrently, so the access to
730   // the isolate_status_ needs to be concurrency-safe.
731   static base::LazyMutex isolate_status_lock_;
732   static std::map<Isolate*, bool> isolate_status_;
733   static std::map<Isolate*, int> isolate_running_streaming_tasks_;
734 
735   static base::LazyMutex cached_code_mutex_;
736   static std::map<std::string, std::unique_ptr<ScriptCompiler::CachedData>>
737       cached_code_map_;
738   static std::atomic<int> unhandled_promise_rejections_;
739 };
740 
741 class FuzzerMonitor : public i::AllStatic {
742  public:
743   static void SimulateErrors();
744 
745  private:
746   static void ControlFlowViolation();
747   static void DCheck();
748   static void Fatal();
749   static void ObservableDifference();
750   static void UndefinedBehavior();
751   static void UseAfterFree();
752   static void UseOfUninitializedValue();
753 };
754 
755 }  // namespace v8
756 
757 #endif  // V8_D8_D8_H_
758