(Same start as #126.)
The external-pointer finalizer (onexit = TRUE) clears the pointer at R shutdown; C entry points don't null-check; deterministic segfault, exit 139, traceback into wsClose.
Reprex:
### R -q -f 03-shutdown-finalizer-segfault.R
library(websocket)
cat("websocket", as.character(packageVersion("websocket")),
"from", find.package("websocket"), "\n")
# websocket 1.4.4 from /Users/r2/Library/R/4.5/websocket
s <- httpuv::startServer("127.0.0.1", httpuv::randomPort(), list(
onWSOpen = function(ws) NULL
))
url <- paste0("ws://127.0.0.1:", s$getPort(), "/")
# A user finalizer that politely closes the websocket at exit.
holder <- new.env()
guard <- new.env()
reg.finalizer(guard, function(e) {
cat("user finalizer: closing websocket\n")
holder$ws$close()
cat("user finalizer: done\n")
}, onexit = TRUE)
# NULL
holder$ws <- WebSocket$new(url)
later::run_now(0.5) # let it open
cat("exiting R now\n")
# exiting R now
q(save = "no")
# user finalizer: closing websocket
# *** caught segfault ***
# address 0x0, cause 'invalid permissions'
# Traceback:
# 1: wsClose(private$wsObj, code, reason)
# 2: holder$ws$close()
# 3: (function (e) { cat("user finalizer: closing websocket\n") ...
# An irrecoverable exception occurred. R is aborting now ...
# Segmentation fault: 11 R -q -f 03-shutdown-finalizer-segfault.R
### echo $? --> 139
(websocket-1.4.4 on in R-4.5.2, confirmed on both macos and ubuntu-24.04)
(Same start as #126.)
The external-pointer finalizer (
onexit = TRUE) clears the pointer at R shutdown; C entry points don't null-check; deterministic segfault, exit 139, traceback intowsClose.Reprex:
(websocket-1.4.4 on in R-4.5.2, confirmed on both macos and ubuntu-24.04)