Commit 919d1dd7 authored by Samuel Groß's avatar Samuel Groß Committed by Commit Bot

Fix unhandled promise rejections in REPRL mode

Previously, unhandled promise rejections weren't reset between REPRL
executions, leading to incorrect exit statuses being reported. This CL
fixes the issue and adds further tests to verify the correct behaviour.

Change-Id: Ied47d9359b0fbc05ebb211667687a0a4041ef767
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2431205Reviewed-by: 's avatarClemens Backes <clemensb@chromium.org>
Reviewed-by: 's avatarMichael Stanton <mvstanton@chromium.org>
Commit-Queue: Samuel Groß <saelo@google.com>
Cr-Commit-Position: refs/heads/master@{#70227}
parent 5f1ae37a
...@@ -1210,6 +1210,7 @@ int PerIsolateData::HandleUnhandledPromiseRejections() { ...@@ -1210,6 +1210,7 @@ int PerIsolateData::HandleUnhandledPromiseRejections() {
Shell::ReportException(isolate_, message, value); Shell::ReportException(isolate_, message, value);
} }
unhandled_promises_.clear(); unhandled_promises_.clear();
ignore_unhandled_promises_ = false;
return static_cast<int>(i); return static_cast<int>(i);
} }
...@@ -3603,6 +3604,9 @@ int Shell::RunMain(Isolate* isolate, bool last_run) { ...@@ -3603,6 +3604,9 @@ int Shell::RunMain(Isolate* isolate, bool last_run) {
printf("%i pending unhandled Promise rejection(s) detected.\n", printf("%i pending unhandled Promise rejection(s) detected.\n",
Shell::unhandled_promise_rejections_.load()); Shell::unhandled_promise_rejections_.load());
success = false; success = false;
// RunMain may be executed multiple times, e.g. in REPRL mode, so we have to
// reset this counter.
Shell::unhandled_promise_rejections_.store(0);
} }
// In order to finish successfully, success must be != expected_to_throw. // In order to finish successfully, success must be != expected_to_throw.
return success == Shell::options.expected_to_throw ? 1 : 0; return success == Shell::options.expected_to_throw ? 1 : 0;
......
...@@ -2,14 +2,13 @@ ...@@ -2,14 +2,13 @@
## Source code ## Source code
On low level fuzzilli communicates with v8 through Swift C API library in `Sources/libreprl/libreprl.c` On a low level, Fuzzilli communicates with v8 through the REPRL protocol, implemented on the fuzzer side by the libreprl C library in `Sources/libreprl/`. The main way of using the library is through the following three functions:
`reprl_spawn_child` fucntions spawns child process. It does that by creating pipes, forking itself, then setting filedescriptors, and then transforming itself using `execve` into v8 process. Afterwords it checks for receiving 4 byte string and it sends the exact same string back. `reprl_create_context()` this creates a new, empty REPRL context to be used by the following APIs.
`fetch_output` fetches the output from the child and returns its size and pointer to data. `reprl_initialize_context(ctx, argv, envp)` this initializes the given context and sets the argv and envp vectors to use for the child processes.
`execute script` `reprl_execute(ctx, code)` this executes the given code and returns the exit status. If necessary, a new child process is created for this. This involves creating pipes, forking itself, then setting filedescriptors, and using `execve` to execute the d8 binary. A child process can be reused for multiple executions, thus increasing fuzzing performance as the overhead of fork and execve are removed.
writes `exec`, and size of script, into the command write pipe and sends script through data write pipe
## Coverage ## Coverage
......
...@@ -5,12 +5,34 @@ ...@@ -5,12 +5,34 @@
extern "C" { extern "C" {
#include <stdio.h> #include <stdio.h>
#include <stdlib.h>
#include <string.h> #include <string.h>
#include "libreprl.h" #include "libreprl.h"
struct reprl_context* ctx;
int execute(const char* code) {
uint64_t exec_time;
return reprl_execute(ctx, code, strlen(code), 1000, &exec_time, 0);
}
void expect_success(const char* code) {
if (execute(code) != 0) {
printf("Execution of \"%s\" failed\n", code);
exit(1);
}
}
void expect_failure(const char* code) {
if (execute(code) == 0) {
printf("Execution of \"%s\" unexpectedly succeeded\n", code);
exit(1);
}
}
int main(int argc, char** argv) { int main(int argc, char** argv) {
struct reprl_context* ctx = reprl_create_context(); ctx = reprl_create_context();
const char* env[] = {nullptr}; const char* env[] = {nullptr};
const char* prog = argc > 1 ? argv[1] : "./out.gn/x64.debug/d8"; const char* prog = argc > 1 ? argv[1] : "./out.gn/x64.debug/d8";
...@@ -20,39 +42,27 @@ int main(int argc, char** argv) { ...@@ -20,39 +42,27 @@ int main(int argc, char** argv) {
return -1; return -1;
} }
uint64_t exec_time;
// Basic functionality test // Basic functionality test
const char* code = "let greeting = \"Hello World!\";"; if (execute("let greeting = \"Hello World!\";") != 0) {
if (reprl_execute(ctx, code, strlen(code), 1000, &exec_time, 0) != 0) { printf(
printf("Execution of \"%s\" failed\n", code); "Script execution failed, is %s the path to d8 built with "
printf("Is %s the path to d8 built with v8_fuzzilli=true?\n", prog); "v8_fuzzilli=true?\n",
prog);
return -1; return -1;
} }
// Verify that runtime exceptions can be detected // Verify that runtime exceptions can be detected
code = "throw 'failure';"; expect_failure("throw 'failure';");
if (reprl_execute(ctx, code, strlen(code), 1000, &exec_time, 0) == 0) {
printf("Execution of \"%s\" unexpectedly succeeded\n", code);
return -1;
}
// Verify that existing state is property reset between executions // Verify that existing state is property reset between executions
code = "globalProp = 42; Object.prototype.foo = \"bar\";"; expect_success("globalProp = 42; Object.prototype.foo = \"bar\";");
if (reprl_execute(ctx, code, strlen(code), 1000, &exec_time, 0) != 0) { expect_success("if (typeof(globalProp) !== 'undefined') throw 'failure'");
printf("Execution of \"%s\" failed\n", code); expect_success("if (typeof(({}).foo) !== 'undefined') throw 'failure'");
return -1;
} // Verify that rejected promises are properly reset between executions
code = "if (typeof(globalProp) !== 'undefined') throw 'failure'"; expect_failure("async function fail() { throw 42; }; fail()");
if (reprl_execute(ctx, code, strlen(code), 1000, &exec_time, 0) != 0) { expect_success("42");
printf("Execution of \"%s\" failed\n", code); expect_failure("async function fail() { throw 42; }; fail()");
return -1;
}
code = "if (typeof(Object.prototype.foo) !== 'undefined') throw 'failure'";
if (reprl_execute(ctx, code, strlen(code), 1000, &exec_time, 0) != 0) {
printf("Execution of \"%s\" failed\n", code);
return -1;
}
puts("OK"); puts("OK");
return 0; return 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment