fix: Hang when recursively logging via ConsoleObject.messageWithTypeAndLevel (#8213)

* Avoid deadlock in messageWithTypeAndLevel by adding a recursion counter

* Add test for recursive logs

* Do not rely on output of console-recursive.test.js

* [autofix.ci] apply automated fixes

---------

Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
This commit is contained in:
Lukas Kastern
2024-01-17 00:26:23 +01:00
committed by GitHub
parent 9350f6bc0b
commit 5a6ef045aa
3 changed files with 66 additions and 4 deletions

View File

@@ -72,6 +72,9 @@ pub const MessageType = enum(u32) {
var stderr_mutex: bun.Lock = bun.Lock.init();
var stdout_mutex: bun.Lock = bun.Lock.init();
threadlocal var stderr_lock_count: u16 = 0;
threadlocal var stdout_lock_count: u16 = 0;
/// https://console.spec.whatwg.org/#formatter
pub fn messageWithTypeAndLevel(
//console_: ConsoleObject.Type,
@@ -92,15 +95,32 @@ pub fn messageWithTypeAndLevel(
// Lock/unlock a mutex incase two JS threads are console.log'ing at the same time
// We do this the slightly annoying way to avoid assigning a pointer
if (level == .Warning or level == .Error or message_type == .Assert) {
stderr_mutex.lock();
if (stderr_lock_count == 0) {
stderr_mutex.lock();
}
stderr_lock_count += 1;
} else {
stdout_mutex.lock();
if (stdout_lock_count == 0) {
stdout_mutex.lock();
}
stdout_lock_count += 1;
}
defer {
if (level == .Warning or level == .Error or message_type == .Assert) {
stderr_mutex.unlock();
stderr_lock_count -= 1;
if (stderr_lock_count == 0) {
stderr_mutex.unlock();
}
} else {
stdout_mutex.unlock();
stdout_lock_count -= 1;
if (stdout_lock_count == 0) {
stdout_mutex.unlock();
}
}
}

View File

@@ -0,0 +1,16 @@
// We use a relatively random string for the stderr flag.
// Just to avoid matching against something in the executable path.
const use_err = process.argv.includes("print_to_stderr_skmxctoznf");
const log_method = use_err ? console.error : console.log;
class MyMap extends Map {
get size() {
log_method("inside size");
return 0;
}
}
const map = new MyMap();
log_method("map:", map);

View File

@@ -0,0 +1,26 @@
// @known-failing-on-windows: 1 failing
import { spawn } from "bun";
import { expect, it } from "bun:test";
import { bunExe, bunEnv } from "harness";
it("should not hang when logging to stdout recursively", async () => {
const { exited } = spawn({
cmd: [bunExe(), import.meta.dir + "/console-recursive.js"],
stdin: null,
stdout: "pipe",
stderr: "pipe",
env: bunEnv,
});
expect(await exited).toBe(0);
});
it("should not hang when logging to stderr recursively", async () => {
const { exited } = spawn({
cmd: [bunExe(), import.meta.dir + "/console-recursive.js", "print_to_stderr_skmxctoznf"],
stdin: null,
stdout: "pipe",
stderr: "pipe",
env: bunEnv,
});
expect(await exited).toBe(0);
});