Skip to content

Switch from extern "C" to extern "C-unwind" #718

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Feb 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .github/workflows/release-windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,6 @@ jobs:
- name: Checkout sources
uses: actions/checkout@v4

- name: Install Rust temporarily pinned to 1.83 (https://github.com/posit-dev/ark/issues/678)
uses: dtolnay/[email protected]

- name: Report Rust version
run: rustc --version

- name: Compile ARK
env:
ARK_BUILD_TYPE: ${{ matrix.flavor }}
Expand Down
2 changes: 1 addition & 1 deletion crates/ark/src/browser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::help::message::ShowHelpUrlParams;
use crate::interface::RMain;

#[harp::register]
pub unsafe extern "C" fn ps_browse_url(url: SEXP) -> anyhow::Result<SEXP> {
pub unsafe extern "C-unwind" fn ps_browse_url(url: SEXP) -> anyhow::Result<SEXP> {
ps_browse_url_impl(url).or_else(|err| {
log::error!("Failed to browse url due to: {err}");
Ok(Rf_ScalarLogical(0))
Expand Down
6 changes: 3 additions & 3 deletions crates/ark/src/connections/r_connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -297,7 +297,7 @@ impl RConnection {
}

#[harp::register]
pub unsafe extern "C" fn ps_connection_opened(
pub unsafe extern "C-unwind" fn ps_connection_opened(
name: SEXP,
host: SEXP,
r#type: SEXP,
Expand Down Expand Up @@ -333,7 +333,7 @@ pub unsafe extern "C" fn ps_connection_opened(
}

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

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

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

Expand Down
2 changes: 1 addition & 1 deletion crates/ark/src/data_explorer/r_data_explorer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1088,7 +1088,7 @@ fn table_info_or_bail(x: SEXP) -> anyhow::Result<TableInfo> {
/// environment; optional.
/// - `env`: The environment containing the R object; optional.
#[harp::register]
pub unsafe extern "C" fn ps_view_data_frame(
pub unsafe extern "C-unwind" fn ps_view_data_frame(
x: SEXP,
title: SEXP,
var: SEXP,
Expand Down
6 changes: 3 additions & 3 deletions crates/ark/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use stdext::unwrap;
use crate::interface::RMain;

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

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

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

Expand All @@ -62,7 +62,7 @@ pub unsafe fn initialize() {
}

#[harp::register]
unsafe extern "C" fn ps_rust_backtrace() -> anyhow::Result<SEXP> {
unsafe extern "C-unwind" fn ps_rust_backtrace() -> anyhow::Result<SEXP> {
let trace = std::backtrace::Backtrace::force_capture();
let trace = format!("{trace}");
Ok(*RObject::from(trace))
Expand Down
14 changes: 7 additions & 7 deletions crates/ark/src/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1973,7 +1973,7 @@ pub(crate) fn console_inputs() -> anyhow::Result<ConsoleInputs> {
// global `RMain` singleton.

#[no_mangle]
pub extern "C" fn r_read_console(
pub extern "C-unwind" fn r_read_console(
prompt: *const c_char,
buf: *mut c_uchar,
buflen: c_int,
Expand Down Expand Up @@ -2018,38 +2018,38 @@ fn new_cstring(x: String) -> CString {
}

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

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

#[no_mangle]
pub extern "C" fn r_busy(which: i32) {
pub extern "C-unwind" fn r_busy(which: i32) {
let main = RMain::get_mut();
main.busy(which);
}

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

#[no_mangle]
pub unsafe extern "C" fn r_polled_events() {
pub unsafe extern "C-unwind" fn r_polled_events() {
let main = RMain::get_mut();
main.polled_events();
}

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

let pkg: String = RObject::view(pkg).try_into()?;
Expand Down
2 changes: 1 addition & 1 deletion crates/ark/src/json.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use libr::SEXP;

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

// Convert the object to a JSON value; this is the core serialization step
Expand Down
4 changes: 2 additions & 2 deletions crates/ark/src/lsp/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use libr::SEXP;

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

#[harp::register]
pub unsafe extern "C" fn ps_object_id(object: SEXP) -> anyhow::Result<SEXP> {
pub unsafe extern "C-unwind" fn ps_object_id(object: SEXP) -> anyhow::Result<SEXP> {
let value = format!("{:p}", object);
return Ok(Rf_mkString(value.as_ptr() as *const c_char));
}
4 changes: 2 additions & 2 deletions crates/ark/src/modules_utils.rs
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
use libr::SEXP;

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

#[harp::register]
pub unsafe extern "C" fn ps_deep_sleep(secs: SEXP) -> anyhow::Result<SEXP> {
pub unsafe extern "C-unwind" fn ps_deep_sleep(secs: SEXP) -> anyhow::Result<SEXP> {
let secs = libr::Rf_asInteger(secs);
let secs = std::time::Duration::from_secs(secs as u64);
std::thread::sleep(secs);
Expand Down
24 changes: 12 additions & 12 deletions crates/ark/src/plots/graphics_device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,11 @@ pub(crate) fn init_graphics_device() {
#[derive(Debug, Default)]
#[allow(non_snake_case)]
struct DeviceCallbacks {
pub activate: Cell<Option<unsafe extern "C" fn(pDevDesc)>>,
pub deactivate: Cell<Option<unsafe extern "C" fn(pDevDesc)>>,
pub holdflush: Cell<Option<unsafe extern "C" fn(pDevDesc, i32) -> i32>>,
pub mode: Cell<Option<unsafe extern "C" fn(i32, pDevDesc)>>,
pub newPage: Cell<Option<unsafe extern "C" fn(pGEcontext, pDevDesc)>>,
pub activate: Cell<Option<unsafe extern "C-unwind" fn(pDevDesc)>>,
pub deactivate: Cell<Option<unsafe extern "C-unwind" fn(pDevDesc)>>,
pub holdflush: Cell<Option<unsafe extern "C-unwind" fn(pDevDesc, i32) -> i32>>,
pub mode: Cell<Option<unsafe extern "C-unwind" fn(i32, pDevDesc)>>,
pub newPage: Cell<Option<unsafe extern "C-unwind" fn(pGEcontext, pDevDesc)>>,
}

#[derive(Default)]
Expand Down Expand Up @@ -473,7 +473,7 @@ pub unsafe fn on_did_execute_request(

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

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

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

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

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

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

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

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

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

#[harp::register]
unsafe extern "C" fn ps_graphics_device() -> anyhow::Result<SEXP> {
unsafe extern "C-unwind" fn ps_graphics_device() -> anyhow::Result<SEXP> {
ps_graphics_device_impl().or_else(|err| {
log::error!("{}", err);
Ok(R_NilValue)
})
}

#[harp::register]
unsafe extern "C" fn ps_graphics_event(_name: SEXP) -> anyhow::Result<SEXP> {
unsafe extern "C-unwind" fn ps_graphics_event(_name: SEXP) -> anyhow::Result<SEXP> {
let id = unwrap!(DEVICE_CONTEXT.with_borrow(|cell| cell._id.borrow().clone()), None => {
return Ok(Rf_ScalarLogical(0));
});
Expand Down
2 changes: 1 addition & 1 deletion crates/ark/src/reticulate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ impl ReticulateService {
// Further actions that reticulate can ask the front-end can be requested through
// the comm_id that is returned by this function.
#[harp::register]
pub unsafe extern "C" fn ps_reticulate_open(input: SEXP) -> Result<SEXP, anyhow::Error> {
pub unsafe extern "C-unwind" fn ps_reticulate_open(input: SEXP) -> Result<SEXP, anyhow::Error> {
let main = RMain::get();

let input: RObject = input.try_into()?;
Expand Down
4 changes: 2 additions & 2 deletions crates/ark/src/srcref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ pub(crate) fn resource_loaded_namespaces() -> anyhow::Result<()> {
}

#[harp::register]
unsafe extern "C" fn ps_ns_populate_srcref(ns_name: SEXP) -> anyhow::Result<SEXP> {
unsafe extern "C-unwind" fn ps_ns_populate_srcref(ns_name: SEXP) -> anyhow::Result<SEXP> {
let ns_name: String = RObject::view(ns_name).try_into()?;
futures::executor::block_on(ns_populate_srcref(ns_name))?;
Ok(harp::r_null())
Expand Down Expand Up @@ -183,6 +183,6 @@ fn generate_source(
}

#[harp::register]
pub extern "C" fn ark_zap_srcref(x: SEXP) -> anyhow::Result<SEXP> {
pub extern "C-unwind" fn ark_zap_srcref(x: SEXP) -> anyhow::Result<SEXP> {
Ok(harp::attrib::zap_srcref(x).sexp)
}
7 changes: 7 additions & 0 deletions crates/ark/src/sys/unix/signals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,13 @@ pub fn set_interrupts_pending(pending: bool) {
}
}

/// Unix interrupt handler
///
/// # Safety
///
/// Note that this can't be `"C-unwind"` because [SigHandler::Handler] takes a `"C"`
/// function, so make absolute sure that the contents of this function can't Rust panic or
/// C longjmp.
pub extern "C" fn handle_interrupt(_signal: libc::c_int) {
set_interrupts_pending(true);
}
4 changes: 2 additions & 2 deletions crates/ark/src/sys/windows/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -180,12 +180,12 @@ fn get_user_home() -> String {
}

#[no_mangle]
extern "C" fn r_callback() {
extern "C-unwind" fn r_callback() {
// Do nothing!
}

#[no_mangle]
extern "C" fn r_yes_no_cancel(question: *const c_char) -> c_int {
extern "C-unwind" fn r_yes_no_cancel(question: *const c_char) -> c_int {
// This seems to only be used on Windows during R's default `CleanUp` when
// `SA_SAVEASK` is used. We should replace `Cleanup` with our own version
// that resolves `SA_SAVEASK`, changes `saveact` to the resolved value,
Expand Down
2 changes: 1 addition & 1 deletion crates/ark/src/traps.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
// and set this up now.
pub use crate::sys::traps::register_trap_handlers;

pub extern "C" fn backtrace_handler(signum: libc::c_int) {
pub extern "C-unwind" fn backtrace_handler(signum: libc::c_int) {
// Prevent infloop into the handler
unsafe {
libc::signal(signum, libc::SIG_DFL);
Expand Down
10 changes: 5 additions & 5 deletions crates/ark/src/ui/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ use libr::SEXP;
use crate::interface::RMain;

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

#[harp::register]
pub unsafe extern "C" fn ps_ui_open_workspace(
pub unsafe extern "C-unwind" fn ps_ui_open_workspace(
path: SEXP,
new_window: SEXP,
) -> anyhow::Result<SEXP> {
Expand All @@ -58,7 +58,7 @@ pub unsafe extern "C" fn ps_ui_open_workspace(
}

#[harp::register]
pub unsafe extern "C" fn ps_ui_navigate_to_file(
pub unsafe extern "C-unwind" fn ps_ui_navigate_to_file(
file: SEXP,
_line: SEXP,
_column: SEXP,
Expand All @@ -81,7 +81,7 @@ pub unsafe extern "C" fn ps_ui_navigate_to_file(
}

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

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

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