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() {
Shell::ReportException(isolate_, message, value);
}
unhandled_promises_.clear();
ignore_unhandled_promises_ = false;
return static_cast<int>(i);
}
......@@ -3603,6 +3604,9 @@ int Shell::RunMain(Isolate* isolate, bool last_run) {
printf("%i pending unhandled Promise rejection(s) detected.\n",
Shell::unhandled_promise_rejections_.load());
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.
return success == Shell::options.expected_to_throw ? 1 : 0;
......
......@@ -2,14 +2,13 @@
## 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`
writes `exec`, and size of script, into the command write pipe and sends script through data write pipe
`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.
## Coverage
......
......@@ -5,12 +5,34 @@
extern "C" {
#include <stdio.h>
#include <stdlib.h>
#include <string.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) {
struct reprl_context* ctx = reprl_create_context();
ctx = reprl_create_context();
const char* env[] = {nullptr};
const char* prog = argc > 1 ? argv[1] : "./out.gn/x64.debug/d8";
......@@ -20,39 +42,27 @@ int main(int argc, char** argv) {
return -1;
}
uint64_t exec_time;
// Basic functionality test
const char* code = "let greeting = \"Hello World!\";";
if (reprl_execute(ctx, code, strlen(code), 1000, &exec_time, 0) != 0) {
printf("Execution of \"%s\" failed\n", code);
printf("Is %s the path to d8 built with v8_fuzzilli=true?\n", prog);
if (execute("let greeting = \"Hello World!\";") != 0) {
printf(
"Script execution failed, is %s the path to d8 built with "
"v8_fuzzilli=true?\n",
prog);
return -1;
}
// Verify that runtime exceptions can be detected
code = "throw 'failure';";
if (reprl_execute(ctx, code, strlen(code), 1000, &exec_time, 0) == 0) {
printf("Execution of \"%s\" unexpectedly succeeded\n", code);
return -1;
}
expect_failure("throw 'failure';");
// Verify that existing state is property reset between executions
code = "globalProp = 42; Object.prototype.foo = \"bar\";";
if (reprl_execute(ctx, code, strlen(code), 1000, &exec_time, 0) != 0) {
printf("Execution of \"%s\" failed\n", code);
return -1;
}
code = "if (typeof(globalProp) !== 'undefined') throw 'failure'";
if (reprl_execute(ctx, code, strlen(code), 1000, &exec_time, 0) != 0) {
printf("Execution of \"%s\" failed\n", code);
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;
}
expect_success("globalProp = 42; Object.prototype.foo = \"bar\";");
expect_success("if (typeof(globalProp) !== 'undefined') throw 'failure'");
expect_success("if (typeof(({}).foo) !== 'undefined') throw 'failure'");
// Verify that rejected promises are properly reset between executions
expect_failure("async function fail() { throw 42; }; fail()");
expect_success("42");
expect_failure("async function fail() { throw 42; }; fail()");
puts("OK");
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