Skip to content

Commit 839eb0b

Browse files
authored
Switch from extern "C" to extern "C-unwind" (#718)
* Minimal but almost certainly wrong Windows unwind solution * Tweak unix specific definition * Change from `extern "C"` to `extern "C-unwind"` * Add note about `extern "C" fn handle_interrupt` * Remove pinning to Rust 1.83
1 parent 6b8833e commit 839eb0b

30 files changed

+379
-239
lines changed

.github/workflows/release-windows.yml

-6
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,6 @@ jobs:
3232
- name: Checkout sources
3333
uses: actions/checkout@v4
3434

35-
- name: Install Rust temporarily pinned to 1.83 (https://github.com/posit-dev/ark/issues/678)
36-
uses: dtolnay/[email protected]
37-
38-
- name: Report Rust version
39-
run: rustc --version
40-
4135
- name: Compile ARK
4236
env:
4337
ARK_BUILD_TYPE: ${{ matrix.flavor }}

crates/ark/src/browser.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use crate::help::message::ShowHelpUrlParams;
1616
use crate::interface::RMain;
1717

1818
#[harp::register]
19-
pub unsafe extern "C" fn ps_browse_url(url: SEXP) -> anyhow::Result<SEXP> {
19+
pub unsafe extern "C-unwind" fn ps_browse_url(url: SEXP) -> anyhow::Result<SEXP> {
2020
ps_browse_url_impl(url).or_else(|err| {
2121
log::error!("Failed to browse url due to: {err}");
2222
Ok(Rf_ScalarLogical(0))

crates/ark/src/connections/r_connection.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ impl RConnection {
297297
}
298298

299299
#[harp::register]
300-
pub unsafe extern "C" fn ps_connection_opened(
300+
pub unsafe extern "C-unwind" fn ps_connection_opened(
301301
name: SEXP,
302302
host: SEXP,
303303
r#type: SEXP,
@@ -333,7 +333,7 @@ pub unsafe extern "C" fn ps_connection_opened(
333333
}
334334

335335
#[harp::register]
336-
pub unsafe extern "C" fn ps_connection_closed(id: SEXP) -> Result<SEXP, anyhow::Error> {
336+
pub unsafe extern "C-unwind" fn ps_connection_closed(id: SEXP) -> Result<SEXP, anyhow::Error> {
337337
let main = RMain::get();
338338
let id_ = RObject::view(id).to::<String>()?;
339339

@@ -344,7 +344,7 @@ pub unsafe extern "C" fn ps_connection_closed(id: SEXP) -> Result<SEXP, anyhow::
344344
}
345345

346346
#[harp::register]
347-
pub unsafe extern "C" fn ps_connection_updated(id: SEXP) -> Result<SEXP, anyhow::Error> {
347+
pub unsafe extern "C-unwind" fn ps_connection_updated(id: SEXP) -> Result<SEXP, anyhow::Error> {
348348
let main = RMain::get();
349349
let comm_id: String = RObject::view(id).to::<String>()?;
350350

crates/ark/src/data_explorer/r_data_explorer.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1088,7 +1088,7 @@ fn table_info_or_bail(x: SEXP) -> anyhow::Result<TableInfo> {
10881088
/// environment; optional.
10891089
/// - `env`: The environment containing the R object; optional.
10901090
#[harp::register]
1091-
pub unsafe extern "C" fn ps_view_data_frame(
1091+
pub unsafe extern "C-unwind" fn ps_view_data_frame(
10921092
x: SEXP,
10931093
title: SEXP,
10941094
var: SEXP,

crates/ark/src/errors.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use stdext::unwrap;
2020
use crate::interface::RMain;
2121

2222
#[harp::register]
23-
unsafe extern "C" fn ps_record_error(evalue: SEXP, traceback: SEXP) -> anyhow::Result<SEXP> {
23+
unsafe extern "C-unwind" fn ps_record_error(evalue: SEXP, traceback: SEXP) -> anyhow::Result<SEXP> {
2424
let main = RMain::get_mut();
2525

2626
// Convert to `RObject` for access to `try_from()` / `try_into()` methods.
@@ -45,7 +45,7 @@ unsafe extern "C" fn ps_record_error(evalue: SEXP, traceback: SEXP) -> anyhow::R
4545
}
4646

4747
#[harp::register]
48-
unsafe extern "C" fn ps_format_traceback(calls: SEXP) -> anyhow::Result<SEXP> {
48+
unsafe extern "C-unwind" fn ps_format_traceback(calls: SEXP) -> anyhow::Result<SEXP> {
4949
Ok(r_format_traceback(calls.into())?.sexp)
5050
}
5151

@@ -62,7 +62,7 @@ pub unsafe fn initialize() {
6262
}
6363

6464
#[harp::register]
65-
unsafe extern "C" fn ps_rust_backtrace() -> anyhow::Result<SEXP> {
65+
unsafe extern "C-unwind" fn ps_rust_backtrace() -> anyhow::Result<SEXP> {
6666
let trace = std::backtrace::Backtrace::force_capture();
6767
let trace = format!("{trace}");
6868
Ok(*RObject::from(trace))

crates/ark/src/interface.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -1989,7 +1989,7 @@ pub(crate) fn console_inputs() -> anyhow::Result<ConsoleInputs> {
19891989
// global `RMain` singleton.
19901990

19911991
#[no_mangle]
1992-
pub extern "C" fn r_read_console(
1992+
pub extern "C-unwind" fn r_read_console(
19931993
prompt: *const c_char,
19941994
buf: *mut c_uchar,
19951995
buflen: c_int,
@@ -2034,38 +2034,38 @@ fn new_cstring(x: String) -> CString {
20342034
}
20352035

20362036
#[no_mangle]
2037-
pub extern "C" fn r_write_console(buf: *const c_char, buflen: i32, otype: i32) {
2037+
pub extern "C-unwind" fn r_write_console(buf: *const c_char, buflen: i32, otype: i32) {
20382038
RMain::write_console(buf, buflen, otype);
20392039
}
20402040

20412041
#[no_mangle]
2042-
pub extern "C" fn r_show_message(buf: *const c_char) {
2042+
pub extern "C-unwind" fn r_show_message(buf: *const c_char) {
20432043
let main = RMain::get();
20442044
main.show_message(buf);
20452045
}
20462046

20472047
#[no_mangle]
2048-
pub extern "C" fn r_busy(which: i32) {
2048+
pub extern "C-unwind" fn r_busy(which: i32) {
20492049
let main = RMain::get_mut();
20502050
main.busy(which);
20512051
}
20522052

20532053
#[no_mangle]
2054-
pub extern "C" fn r_suicide(buf: *const c_char) {
2054+
pub extern "C-unwind" fn r_suicide(buf: *const c_char) {
20552055
let msg = unsafe { CStr::from_ptr(buf) };
20562056
panic!("Suicide: {}", msg.to_str().unwrap());
20572057
}
20582058

20592059
#[no_mangle]
2060-
pub unsafe extern "C" fn r_polled_events() {
2060+
pub unsafe extern "C-unwind" fn r_polled_events() {
20612061
let main = RMain::get_mut();
20622062
main.polled_events();
20632063
}
20642064

20652065
// This hook is called like a user onLoad hook but for every package to be
20662066
// loaded in the session
20672067
#[harp::register]
2068-
unsafe extern "C" fn ps_onload_hook(pkg: SEXP, _path: SEXP) -> anyhow::Result<SEXP> {
2068+
unsafe extern "C-unwind" fn ps_onload_hook(pkg: SEXP, _path: SEXP) -> anyhow::Result<SEXP> {
20692069
// NOTE: `_path` might be NULL for a compat reason, see comments on the R side
20702070

20712071
let pkg: String = RObject::view(pkg).try_into()?;

crates/ark/src/json.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use libr::SEXP;
1010

1111
/// Convenience method to convert a JSON object to a string
1212
#[harp::register]
13-
pub unsafe extern "C" fn ps_to_json(obj: SEXP) -> anyhow::Result<SEXP> {
13+
pub unsafe extern "C-unwind" fn ps_to_json(obj: SEXP) -> anyhow::Result<SEXP> {
1414
let obj = RObject::view(obj);
1515

1616
// Convert the object to a JSON value; this is the core serialization step

crates/ark/src/lsp/util.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ use libr::SEXP;
1414

1515
/// Shows a message in the Positron frontend
1616
#[harp::register]
17-
pub unsafe extern "C" fn ps_log_error(message: SEXP) -> anyhow::Result<SEXP> {
17+
pub unsafe extern "C-unwind" fn ps_log_error(message: SEXP) -> anyhow::Result<SEXP> {
1818
let message = RObject::view(message).to::<String>();
1919
if let Ok(message) = message {
2020
log::error!("{}", message);
@@ -24,7 +24,7 @@ pub unsafe extern "C" fn ps_log_error(message: SEXP) -> anyhow::Result<SEXP> {
2424
}
2525

2626
#[harp::register]
27-
pub unsafe extern "C" fn ps_object_id(object: SEXP) -> anyhow::Result<SEXP> {
27+
pub unsafe extern "C-unwind" fn ps_object_id(object: SEXP) -> anyhow::Result<SEXP> {
2828
let value = format!("{:p}", object);
2929
return Ok(Rf_mkString(value.as_ptr() as *const c_char));
3030
}

crates/ark/src/modules_utils.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
use libr::SEXP;
22

33
#[harp::register]
4-
pub unsafe extern "C" fn ark_node_poke_cdr(node: SEXP, cdr: SEXP) -> anyhow::Result<SEXP> {
4+
pub unsafe extern "C-unwind" fn ark_node_poke_cdr(node: SEXP, cdr: SEXP) -> anyhow::Result<SEXP> {
55
libr::SETCDR(node, cdr);
66
return Ok(harp::r_null());
77
}
88

99
#[harp::register]
10-
pub unsafe extern "C" fn ps_deep_sleep(secs: SEXP) -> anyhow::Result<SEXP> {
10+
pub unsafe extern "C-unwind" fn ps_deep_sleep(secs: SEXP) -> anyhow::Result<SEXP> {
1111
let secs = libr::Rf_asInteger(secs);
1212
let secs = std::time::Duration::from_secs(secs as u64);
1313
std::thread::sleep(secs);

crates/ark/src/plots/graphics_device.rs

+12-12
Original file line numberDiff line numberDiff line change
@@ -77,11 +77,11 @@ pub(crate) fn init_graphics_device() {
7777
#[derive(Debug, Default)]
7878
#[allow(non_snake_case)]
7979
struct DeviceCallbacks {
80-
pub activate: Cell<Option<unsafe extern "C" fn(pDevDesc)>>,
81-
pub deactivate: Cell<Option<unsafe extern "C" fn(pDevDesc)>>,
82-
pub holdflush: Cell<Option<unsafe extern "C" fn(pDevDesc, i32) -> i32>>,
83-
pub mode: Cell<Option<unsafe extern "C" fn(i32, pDevDesc)>>,
84-
pub newPage: Cell<Option<unsafe extern "C" fn(pGEcontext, pDevDesc)>>,
80+
pub activate: Cell<Option<unsafe extern "C-unwind" fn(pDevDesc)>>,
81+
pub deactivate: Cell<Option<unsafe extern "C-unwind" fn(pDevDesc)>>,
82+
pub holdflush: Cell<Option<unsafe extern "C-unwind" fn(pDevDesc, i32) -> i32>>,
83+
pub mode: Cell<Option<unsafe extern "C-unwind" fn(i32, pDevDesc)>>,
84+
pub newPage: Cell<Option<unsafe extern "C-unwind" fn(pGEcontext, pDevDesc)>>,
8585
}
8686

8787
#[derive(Default)]
@@ -473,7 +473,7 @@ pub unsafe fn on_did_execute_request(
473473

474474
// NOTE: May be called when rendering a plot to file, since this is done by
475475
// copying the graphics display list to a new plot device, and then closing that device.
476-
unsafe extern "C" fn gd_activate(dev: pDevDesc) {
476+
unsafe extern "C-unwind" fn gd_activate(dev: pDevDesc) {
477477
log::trace!("gd_activate");
478478

479479
DEVICE_CONTEXT.with_borrow(|cell| {
@@ -485,7 +485,7 @@ unsafe extern "C" fn gd_activate(dev: pDevDesc) {
485485

486486
// NOTE: May be called when rendering a plot to file, since this is done by
487487
// copying the graphics display list to a new plot device, and then closing that device.
488-
unsafe extern "C" fn gd_deactivate(dev: pDevDesc) {
488+
unsafe extern "C-unwind" fn gd_deactivate(dev: pDevDesc) {
489489
log::trace!("gd_deactivate");
490490

491491
DEVICE_CONTEXT.with_borrow(|cell| {
@@ -495,7 +495,7 @@ unsafe extern "C" fn gd_deactivate(dev: pDevDesc) {
495495
});
496496
}
497497

498-
unsafe extern "C" fn gd_hold_flush(dev: pDevDesc, mut holdflush: i32) -> i32 {
498+
unsafe extern "C-unwind" fn gd_hold_flush(dev: pDevDesc, mut holdflush: i32) -> i32 {
499499
log::trace!("gd_hold_flush");
500500

501501
DEVICE_CONTEXT.with_borrow(|cell| {
@@ -511,7 +511,7 @@ unsafe extern "C" fn gd_hold_flush(dev: pDevDesc, mut holdflush: i32) -> i32 {
511511
// mode = 0, graphics off
512512
// mode = 1, graphics on
513513
// mode = 2, graphical input on (ignored by most drivers)
514-
unsafe extern "C" fn gd_mode(mode: i32, dev: pDevDesc) {
514+
unsafe extern "C-unwind" fn gd_mode(mode: i32, dev: pDevDesc) {
515515
log::trace!("gd_mode: {mode}");
516516

517517
DEVICE_CONTEXT.with_borrow(|cell| {
@@ -522,7 +522,7 @@ unsafe extern "C" fn gd_mode(mode: i32, dev: pDevDesc) {
522522
});
523523
}
524524

525-
unsafe extern "C" fn gd_new_page(dd: pGEcontext, dev: pDevDesc) {
525+
unsafe extern "C-unwind" fn gd_new_page(dd: pGEcontext, dev: pDevDesc) {
526526
log::trace!("gd_new_page");
527527

528528
DEVICE_CONTEXT.with_borrow(|cell| {
@@ -590,15 +590,15 @@ unsafe fn ps_graphics_device_impl() -> anyhow::Result<SEXP> {
590590
}
591591

592592
#[harp::register]
593-
unsafe extern "C" fn ps_graphics_device() -> anyhow::Result<SEXP> {
593+
unsafe extern "C-unwind" fn ps_graphics_device() -> anyhow::Result<SEXP> {
594594
ps_graphics_device_impl().or_else(|err| {
595595
log::error!("{}", err);
596596
Ok(R_NilValue)
597597
})
598598
}
599599

600600
#[harp::register]
601-
unsafe extern "C" fn ps_graphics_event(_name: SEXP) -> anyhow::Result<SEXP> {
601+
unsafe extern "C-unwind" fn ps_graphics_event(_name: SEXP) -> anyhow::Result<SEXP> {
602602
let id = unwrap!(DEVICE_CONTEXT.with_borrow(|cell| cell._id.borrow().clone()), None => {
603603
return Ok(Rf_ScalarLogical(0));
604604
});

crates/ark/src/reticulate.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ impl ReticulateService {
8585
// Further actions that reticulate can ask the front-end can be requested through
8686
// the comm_id that is returned by this function.
8787
#[harp::register]
88-
pub unsafe extern "C" fn ps_reticulate_open(input: SEXP) -> Result<SEXP, anyhow::Error> {
88+
pub unsafe extern "C-unwind" fn ps_reticulate_open(input: SEXP) -> Result<SEXP, anyhow::Error> {
8989
let main = RMain::get();
9090

9191
let input: RObject = input.try_into()?;

crates/ark/src/srcref.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ unsafe extern "C" fn ps_resource_namespaces(pkgs: SEXP) -> anyhow::Result<SEXP>
4343
}
4444

4545
#[harp::register]
46-
unsafe extern "C" fn ps_ns_populate_srcref(ns_name: SEXP) -> anyhow::Result<SEXP> {
46+
unsafe extern "C-unwind" fn ps_ns_populate_srcref(ns_name: SEXP) -> anyhow::Result<SEXP> {
4747
let ns_name: String = RObject::view(ns_name).try_into()?;
4848
futures::executor::block_on(ns_populate_srcref(ns_name))?;
4949
Ok(harp::r_null())
@@ -194,6 +194,6 @@ fn generate_source(
194194
}
195195

196196
#[harp::register]
197-
pub extern "C" fn ark_zap_srcref(x: SEXP) -> anyhow::Result<SEXP> {
197+
pub extern "C-unwind" fn ark_zap_srcref(x: SEXP) -> anyhow::Result<SEXP> {
198198
Ok(harp::attrib::zap_srcref(x).sexp)
199199
}

crates/ark/src/sys/unix/signals.rs

+7
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,13 @@ pub fn set_interrupts_pending(pending: bool) {
6464
}
6565
}
6666

67+
/// Unix interrupt handler
68+
///
69+
/// # Safety
70+
///
71+
/// Note that this can't be `"C-unwind"` because [SigHandler::Handler] takes a `"C"`
72+
/// function, so make absolute sure that the contents of this function can't Rust panic or
73+
/// C longjmp.
6774
pub extern "C" fn handle_interrupt(_signal: libc::c_int) {
6875
set_interrupts_pending(true);
6976
}

crates/ark/src/sys/windows/interface.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -180,12 +180,12 @@ fn get_user_home() -> String {
180180
}
181181

182182
#[no_mangle]
183-
extern "C" fn r_callback() {
183+
extern "C-unwind" fn r_callback() {
184184
// Do nothing!
185185
}
186186

187187
#[no_mangle]
188-
extern "C" fn r_yes_no_cancel(question: *const c_char) -> c_int {
188+
extern "C-unwind" fn r_yes_no_cancel(question: *const c_char) -> c_int {
189189
// This seems to only be used on Windows during R's default `CleanUp` when
190190
// `SA_SAVEASK` is used. We should replace `Cleanup` with our own version
191191
// that resolves `SA_SAVEASK`, changes `saveact` to the resolved value,

crates/ark/src/traps.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
// and set this up now.
2323
pub use crate::sys::traps::register_trap_handlers;
2424

25-
pub extern "C" fn backtrace_handler(signum: libc::c_int) {
25+
pub extern "C-unwind" fn backtrace_handler(signum: libc::c_int) {
2626
// Prevent infloop into the handler
2727
unsafe {
2828
libc::signal(signum, libc::SIG_DFL);

crates/ark/src/ui/events.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use libr::SEXP;
2020
use crate::interface::RMain;
2121

2222
#[harp::register]
23-
pub unsafe extern "C" fn ps_ui_show_message(message: SEXP) -> anyhow::Result<SEXP> {
23+
pub unsafe extern "C-unwind" fn ps_ui_show_message(message: SEXP) -> anyhow::Result<SEXP> {
2424
let params = ShowMessageParams {
2525
message: RObject::view(message).try_into()?,
2626
};
@@ -37,7 +37,7 @@ pub unsafe extern "C" fn ps_ui_show_message(message: SEXP) -> anyhow::Result<SEX
3737
}
3838

3939
#[harp::register]
40-
pub unsafe extern "C" fn ps_ui_open_workspace(
40+
pub unsafe extern "C-unwind" fn ps_ui_open_workspace(
4141
path: SEXP,
4242
new_window: SEXP,
4343
) -> anyhow::Result<SEXP> {
@@ -58,7 +58,7 @@ pub unsafe extern "C" fn ps_ui_open_workspace(
5858
}
5959

6060
#[harp::register]
61-
pub unsafe extern "C" fn ps_ui_navigate_to_file(
61+
pub unsafe extern "C-unwind" fn ps_ui_navigate_to_file(
6262
file: SEXP,
6363
_line: SEXP,
6464
_column: SEXP,
@@ -81,7 +81,7 @@ pub unsafe extern "C" fn ps_ui_navigate_to_file(
8181
}
8282

8383
#[harp::register]
84-
pub unsafe extern "C" fn ps_ui_set_selection_ranges(ranges: SEXP) -> anyhow::Result<SEXP> {
84+
pub unsafe extern "C-unwind" fn ps_ui_set_selection_ranges(ranges: SEXP) -> anyhow::Result<SEXP> {
8585
let selections = ps_ui_robj_as_ranges(ranges)?;
8686
let params = SetEditorSelectionsParams { selections };
8787

@@ -97,7 +97,7 @@ pub unsafe extern "C" fn ps_ui_set_selection_ranges(ranges: SEXP) -> anyhow::Res
9797
}
9898

9999
#[harp::register]
100-
pub unsafe extern "C" fn ps_ui_show_url(url: SEXP) -> anyhow::Result<SEXP> {
100+
pub unsafe extern "C-unwind" fn ps_ui_show_url(url: SEXP) -> anyhow::Result<SEXP> {
101101
let params = ShowUrlParams {
102102
url: RObject::view(url).try_into()?,
103103
};

0 commit comments

Comments
 (0)