jatorre opened a new issue, #4178:
URL: https://github.com/apache/arrow-adbc/issues/4178
## Description
`release_ffi_error` in `rust/core/adbc_ffi/src/types.rs` frees
`error.message` and `error.private_data` but does not null the pointers or
clear the `release` callback afterward. If the release function is called a
second time (e.g. by a C++ RAII destructor in the ADBC driver manager), the
stale pointers cause a double-free.
## Reproduction
Any Rust ADBC driver built with `adbc_ffi` v0.22 crashes when loaded through
DuckDB's `adbc_scanner` extension (v1.5.0):
```sql
LOAD adbc_scanner;
SELECT adbc_connect({'driver': '/path/to/rust_driver.so'});
-- Crashes: "free(): double free detected in tcache 2"
```
GDB backtrace confirms the crash is in `release_ffi_error`:
```
#6 _int_free (have_lock=0) at ./malloc/malloc.c:4473
#7 __GI___libc_free at ./malloc/malloc.c:3391
#8 release_ffi_error from libadbc_driver_databricks.so
#9 CreateConnectionFromOptions from adbc_scanner.duckdb_extension
```
The same driver works fine when called from a plain C test harness that only
calls `error.release` once.
## Root cause
`release_ffi_error` (types.rs, line 559):
```rust
unsafe extern "C" fn release_ffi_error(error: *mut FFI_AdbcError) {
match error.as_mut() {
None => (),
Some(error) => {
drop(CString::from_raw(error.message)); // frees message
// BUG: error.message still points to freed memory
if !error.private_data.is_null() {
let private_data = Box::from_raw(error.private_data as *mut
ErrorPrivateData);
drop(private_data);
// BUG: error.private_data still points to freed memory
}
// BUG: error.release still set — second call will re-enter
}
}
}
```
## Suggested fix
Null pointers and clear the callback after freeing:
```rust
unsafe extern "C" fn release_ffi_error(error: *mut FFI_AdbcError) {
match error.as_mut() {
None => (),
Some(error) => {
if !error.message.is_null() {
drop(CString::from_raw(error.message));
error.message = null_mut();
}
if !error.private_data.is_null() {
let private_data = Box::from_raw(error.private_data as *mut
ErrorPrivateData);
drop(private_data);
error.private_data = null_mut();
}
error.release = None;
}
}
}
```
This matches the pattern used by arrow-rs's
`FFI_ArrowArrayStream::release_stream`, which nulls all callbacks and the
release field.
## Environment
- `adbc_ffi` v0.22.0 (crates.io)
- DuckDB v1.5.0 with `adbc_scanner` community extension (arrow-adbc v22 via
vcpkg)
- Linux aarch64, glibc 2.35
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]