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]

Reply via email to