Skip to content

Commit 7ce9d87

Browse files
Merge branch 'main' into claude/tls-close-write-spill
2 parents 31345e4 + ba04159 commit 7ce9d87

10 files changed

Lines changed: 472 additions & 39 deletions

File tree

packages/bun-usockets/src/context.c

Lines changed: 41 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,17 @@ struct us_listen_socket_t *us_socket_group_listen(struct us_socket_group_t *grou
373373

374374
struct us_poll_t *p = us_create_poll(group->loop, 0, sizeof(struct us_listen_socket_t));
375375
us_poll_init(p, listen_socket_fd, POLL_TYPE_SEMI_SOCKET);
376-
us_poll_start(p, group->loop, LIBUS_SOCKET_READABLE);
376+
if (us_poll_start_rc(p, group->loop, LIBUS_SOCKET_READABLE) != 0) {
377+
/* EPOLL_CTL_ADD failed (e.g. ENOSPC at fs.epoll.max_user_watches).
378+
* Report via both the out-param and thread-local errno: Bun.listen
379+
* reads *error, Bun.serve reads errno. */
380+
int saved_errno = errno;
381+
bsd_close_socket(listen_socket_fd);
382+
us_poll_free(p, group->loop);
383+
*error = saved_errno;
384+
errno = saved_errno;
385+
return 0;
386+
}
377387

378388
struct us_listen_socket_t *ls = (struct us_listen_socket_t *) p;
379389
us_internal_init_listen_socket(ls, group, kind, ssl_ctx, options, socket_ext_size);
@@ -395,7 +405,14 @@ struct us_listen_socket_t *us_socket_group_listen_unix(struct us_socket_group_t
395405

396406
struct us_poll_t *p = us_create_poll(group->loop, 0, sizeof(struct us_listen_socket_t));
397407
us_poll_init(p, listen_socket_fd, POLL_TYPE_SEMI_SOCKET);
398-
us_poll_start(p, group->loop, LIBUS_SOCKET_READABLE);
408+
if (us_poll_start_rc(p, group->loop, LIBUS_SOCKET_READABLE) != 0) {
409+
int saved_errno = errno;
410+
bsd_close_socket(listen_socket_fd);
411+
us_poll_free(p, group->loop);
412+
*error = saved_errno;
413+
errno = saved_errno;
414+
return 0;
415+
}
399416

400417
struct us_listen_socket_t *ls = (struct us_listen_socket_t *) p;
401418
us_internal_init_listen_socket(ls, group, kind, ssl_ctx, options, socket_ext_size);
@@ -485,7 +502,13 @@ struct us_socket_t *us_socket_group_connect_resolved_dns(struct us_socket_group_
485502

486503
struct us_poll_t *p = us_create_poll(group->loop, 0, sizeof(struct us_socket_t) + socket_ext_size);
487504
us_poll_init(p, connect_socket_fd, POLL_TYPE_SEMI_SOCKET);
488-
us_poll_start(p, group->loop, LIBUS_SOCKET_WRITABLE);
505+
if (us_poll_start_rc(p, group->loop, LIBUS_SOCKET_WRITABLE) != 0) {
506+
int saved_errno = errno;
507+
bsd_close_socket(connect_socket_fd);
508+
us_poll_free(p, group->loop);
509+
errno = saved_errno;
510+
return NULL;
511+
}
489512

490513
struct us_socket_t *socket = (struct us_socket_t *) p;
491514
us_internal_init_connect_socket(socket, group, kind, options);
@@ -616,7 +639,13 @@ struct us_socket_t *us_socket_group_connect_unix(struct us_socket_group_t *group
616639

617640
struct us_poll_t *p = us_create_poll(group->loop, 0, sizeof(struct us_socket_t) + socket_ext_size);
618641
us_poll_init(p, connect_socket_fd, POLL_TYPE_SEMI_SOCKET);
619-
us_poll_start(p, group->loop, LIBUS_SOCKET_WRITABLE);
642+
if (us_poll_start_rc(p, group->loop, LIBUS_SOCKET_WRITABLE) != 0) {
643+
int saved_errno = errno;
644+
bsd_close_socket(connect_socket_fd);
645+
us_poll_free(p, group->loop);
646+
errno = saved_errno;
647+
return 0;
648+
}
620649

621650
struct us_socket_t *connect_socket = (struct us_socket_t *) p;
622651
us_internal_init_connect_socket(connect_socket, group, kind, options);
@@ -641,9 +670,16 @@ int start_connections(struct us_connecting_socket_t *c, int count) {
641670
if (connect_socket_fd == LIBUS_SOCKET_ERROR) {
642671
continue;
643672
}
644-
++opened;
645673
bsd_socket_nodelay(connect_socket_fd, 1);
646674
struct us_socket_t *s = (struct us_socket_t *)us_create_poll(loop, 0, sizeof(struct us_socket_t) + c->socket_ext_size);
675+
struct us_poll_t *poll = &s->p;
676+
us_poll_init(poll, connect_socket_fd, POLL_TYPE_SEMI_SOCKET);
677+
if (us_poll_start_rc(poll, loop, LIBUS_SOCKET_WRITABLE) != 0) {
678+
bsd_close_socket(connect_socket_fd);
679+
us_poll_free(poll, loop);
680+
continue;
681+
}
682+
++opened;
647683
us_internal_init_connect_socket(s, group, c->kind, c->options);
648684
s->timeout = c->timeout;
649685
s->long_timeout = c->long_timeout;
@@ -655,10 +691,6 @@ int start_connections(struct us_connecting_socket_t *c, int count) {
655691
s->connect_next = c->connecting_head;
656692
c->connecting_head = s;
657693
s->connect_state = c;
658-
659-
struct us_poll_t *poll = &s->p;
660-
us_poll_init(poll, connect_socket_fd, POLL_TYPE_SEMI_SOCKET);
661-
us_poll_start(poll, loop, LIBUS_SOCKET_WRITABLE);
662694
}
663695
return opened;
664696
}

packages/bun-usockets/src/eventing/epoll_kqueue.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,13 @@ int kqueue_change(int kqfd, int fd, int old_events, int new_events, void *user_d
468468

469469
// ret should be 0 in most cases (not guaranteed when removing async)
470470

471+
/* KEVENT_FLAG_ERROR_EVENTS reports per-filter failures as EV_ERROR entries
472+
* with the errno in .data; kevent64 itself returns the count and does not
473+
* set errno. Mirror epoll's contract so us_poll_start_rc callers can read it. */
474+
if (ret > 0) {
475+
errno = (int) change_list[0].data;
476+
}
477+
471478
return ret;
472479
}
473480
#endif

packages/bun-usockets/src/eventing/libuv.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,11 @@ void us_poll_start(struct us_poll_t *p, struct us_loop_t *loop, int events) {
104104
uv_poll_start(p->uv_p, events, poll_cb);
105105
}
106106

107+
int us_poll_start_rc(struct us_poll_t *p, struct us_loop_t *loop, int events) {
108+
us_poll_start(p, loop, events);
109+
return 0;
110+
}
111+
107112
void us_poll_change(struct us_poll_t *p, struct us_loop_t *loop, int events) {
108113
if(!p->uv_p) return;
109114
if (us_poll_events(p) != events) {

packages/bun-usockets/src/loop.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,14 @@ void us_internal_dispatch_ready_poll(struct us_poll_t *p, int error, int eof, in
420420
do {
421421
struct us_poll_t *accepted_p = us_create_poll(loop, 0, sizeof(struct us_socket_t) - sizeof(struct us_poll_t) + listen_socket->socket_ext_size);
422422
us_poll_init(accepted_p, client_fd, POLL_TYPE_SOCKET);
423-
us_poll_start(accepted_p, loop, LIBUS_SOCKET_READABLE);
423+
if (us_poll_start_rc(accepted_p, loop, LIBUS_SOCKET_READABLE) != 0) {
424+
/* EPOLL_CTL_ADD failed (e.g. ENOSPC). Close the fd so the
425+
* peer sees a RST instead of a connection that silently
426+
* never answers. */
427+
bsd_close_socket(client_fd);
428+
us_poll_free(accepted_p, loop);
429+
continue;
430+
}
424431

425432
struct us_socket_t *s = (struct us_socket_t *) accepted_p;
426433

packages/bun-usockets/src/udp.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,14 @@ struct us_udp_socket_t *us_create_udp_socket(
169169

170170
struct us_poll_t *p = us_create_poll(loop, fallthrough, sizeof(struct us_udp_socket_t) + ext_size);
171171
us_poll_init(p, fd, POLL_TYPE_UDP);
172+
if (us_poll_start_rc(p, loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE) != 0) {
173+
int saved_errno = errno;
174+
bsd_close_socket(fd);
175+
us_poll_free(p, loop);
176+
if (err) *err = saved_errno;
177+
errno = saved_errno;
178+
return 0;
179+
}
172180

173181
struct us_udp_socket_t *udp = (struct us_udp_socket_t *)p;
174182

@@ -190,7 +198,5 @@ struct us_udp_socket_t *us_create_udp_socket(
190198
udp->on_recv_error = recv_error_cb;
191199
udp->next = NULL;
192200

193-
us_poll_start((struct us_poll_t *) udp, udp->loop, LIBUS_SOCKET_READABLE | LIBUS_SOCKET_WRITABLE);
194-
195201
return (struct us_udp_socket_t *) udp;
196202
}

src/js/internal-for-testing.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -300,17 +300,17 @@ export type SocketFaultRule = {
300300

301301
export const socketFaultInjection = {
302302
/** True when the current binary was built with `--socket-fault-injection=on` (defaults to on for ASan builds). */
303-
available: $newZigFunction(
304-
"runtime/socket/socket.zig",
303+
available: $newRustFunction(
304+
"runtime/socket/socket.rs",
305305
"TestingAPIs.jsSocketFaultInjectionAvailable",
306306
0,
307307
) as () => boolean,
308308
/** Arm a process-wide fault rule for one usockets bsd_* syscall. */
309-
set: $newZigFunction("runtime/socket/socket.zig", "TestingAPIs.jsSetSocketFault", 1) as (
309+
set: $newRustFunction("runtime/socket/socket.rs", "TestingAPIs.jsSetSocketFault", 1) as (
310310
rule: SocketFaultRule,
311311
) => boolean,
312312
/** Disarm all fault rules. */
313-
clear: $newZigFunction("runtime/socket/socket.zig", "TestingAPIs.jsClearSocketFaults", 0) as () => void,
313+
clear: $newRustFunction("runtime/socket/socket.rs", "TestingAPIs.jsClearSocketFaults", 0) as () => void,
314314
};
315315
type SerializationContext = "worker" | "window" | "postMessage" | "default";
316316
export const structuredCloneAdvanced: (

src/runtime/api/YAMLObject.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -641,16 +641,16 @@ impl Stringifier {
641641
0x7f => self.builder.append_latin1(b"\\x7f"), // delete
642642
0x85 => self.builder.append_latin1(b"\\N"), // next line
643643
0xa0 => self.builder.append_latin1(b"\\_"), // non-breaking space
644-
0xa8 => self.builder.append_latin1(b"\\L"), // line separator
645-
0xa9 => self.builder.append_latin1(b"\\P"), // paragraph separator
644+
0x2028 => self.builder.append_latin1(b"\\L"), // line separator
645+
0x2029 => self.builder.append_latin1(b"\\P"), // paragraph separator
646646

647647
0x20..=0x21
648648
| 0x23..=0x5b
649649
| 0x5d..=0x7e
650650
| 0x80..=0x84
651651
| 0x86..=0x9f
652-
| 0xa1..=0xa7
653-
| 0xaa..=u16::MAX => self.builder.append_uchar(c),
652+
| 0xa1..=0x2027
653+
| 0x202a..=u16::MAX => self.builder.append_uchar(c),
654654
}
655655
}
656656

@@ -883,8 +883,8 @@ fn string_needs_quotes(str: &BunString) -> bool {
883883
| 0x7f
884884
| 0x85
885885
| 0xa0
886-
| 0xa8
887-
| 0xa9 => return true,
886+
| 0x2028
887+
| 0x2029 => return true,
888888

889889
_ => {
890890
i += 1;

src/runtime/server/mod.rs

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1736,23 +1736,37 @@ impl<const SSL: bool, const DEBUG: bool> NewServer<SSL, DEBUG> {
17361736
// Rust's `target_os = "linux"` excludes
17371737
// Android, so match both explicitly.
17381738
#[cfg(any(target_os = "linux", target_os = "android"))]
1739-
if bun_sys::get_errno(-1i32) == bun_sys::E::EACCES {
1740-
let host = _hostname
1741-
.as_ref()
1742-
.map(|h| h.as_bytes())
1743-
.unwrap_or(b"0.0.0.0");
1744-
let err = jsc::SystemError {
1745-
message: bun_core::String::create_format(format_args!(
1746-
"permission denied {}:{}",
1747-
bstr::BStr::new(host),
1748-
port
1749-
)),
1750-
code: bun_core::String::static_("EACCES"),
1751-
syscall: bun_core::String::static_("listen"),
1752-
..Default::default()
1753-
};
1754-
let _ = global.throw_value(err.to_error_instance(global));
1755-
return;
1739+
{
1740+
let errno = bun_sys::get_errno(-1i32);
1741+
if errno == bun_sys::E::EACCES {
1742+
let host = _hostname
1743+
.as_ref()
1744+
.map(|h| h.as_bytes())
1745+
.unwrap_or(b"0.0.0.0");
1746+
let err = jsc::SystemError {
1747+
message: bun_core::String::create_format(format_args!(
1748+
"permission denied {}:{}",
1749+
bstr::BStr::new(host),
1750+
port
1751+
)),
1752+
code: bun_core::String::static_("EACCES"),
1753+
syscall: bun_core::String::static_("listen"),
1754+
..Default::default()
1755+
};
1756+
let _ = global.throw_value(err.to_error_instance(global));
1757+
return;
1758+
}
1759+
// e.g. ENOSPC from epoll_ctl(EPOLL_CTL_ADD). Linux-only because
1760+
// on other platforms errno is not reliably preserved through
1761+
// the C++/callback chain to here; see PR #30364.
1762+
if errno != bun_sys::E::SUCCESS && errno != bun_sys::E::EADDRINUSE {
1763+
let err = jsc::SystemError::from(
1764+
bun_sys::Error::from_code(errno, bun_sys::Tag::listen)
1765+
.to_system_error(),
1766+
);
1767+
let _ = global.throw_value(err.to_error_instance(global));
1768+
return;
1769+
}
17561770
}
17571771
jsc::SystemError {
17581772
message: bun_core::String::create_format(format_args!(

0 commit comments

Comments
 (0)