pedrobtz opened a new issue, #53951:
URL: https://github.com/apache/arrow/issues/53951

   ### Describe the bug, including details regarding any error messages, 
version, and platform.
   
   Making an R object for an extension type that was not defined in R (a C++ 
extension type such as the canonical `arrow.opaque`) crashes R. Everything that 
goes through `ExtensionType$new()` does it: `as_data_type()` on such a schema, 
`as_arrow_array()`, `arrow_table()`, and so on.
   
   Minimal reproduction, using only nanoarrow to build the schema:
   
   ```r
   library(nanoarrow)
   s <- na_fixed_size_binary(16)
   s <- nanoarrow_schema_modify(s, list(metadata = list(
     "ARROW:extension:name" = "arrow.opaque",
     "ARROW:extension:metadata" = 
'{"type_name":"hugeint","vendor_name":"DuckDB"}'
   )))
   arrow::as_data_type(s)
   ```
   
   ```
    *** caught segfault ***          (arrow 25.0.1; a bus error with arrow 
24.0.0)
   Traceback:
    1: ExtensionType__r6_class(self)
    2: super$r6_class()
    3: ExtensionType$new(<pointer: 0x...>)
    4: getFromNamespace("DataType", "arrow")$import_from_c(exportable_schema)
    5: as_data_type.nanoarrow_schema(s)
   ```
   
   Seen with arrow 25.0.1 and 24.0.0 (CRAN binaries), nanoarrow 0.9.0, R 4.6.1 
on macOS arm64; also as a segfault through `arrow_table()`. Tables built 
without making that R object (for example `as_arrow_table()` on a nanoarrow 
struct array, or reading Parquet) carry the column fine.
   
   **Cause.** `ExtensionType__r6_class()` in `r/src/extension-impl.cpp` casts 
any `arrow::ExtensionType` to `RExtensionType`:
   
   ```cpp
   cpp11::environment ExtensionType__r6_class(
       const std::shared_ptr<arrow::ExtensionType>& type) {
     auto r_type =
         arrow::internal::checked_pointer_cast<RExtensionType, 
arrow::ExtensionType>(type);
     return r_type->r6_class();
   }
   ```
   
   `checked_pointer_cast` is a `static_pointer_cast` in release builds, so for 
an extension type that is not an `RExtensionType`, such as 
`arrow::extension::OpaqueType`, `r6_class()` reads unrelated memory. This is 
the same bug as #49956 in the GLib bindings (an unconditional cast to 
`GExtensionType`), which names R-arrow among the affected bindings but was 
fixed in GLib only.
   
   A fix in the same spirit: `dynamic_pointer_cast` to `RExtensionType`, and 
when that fails return the plain `ExtensionType` R6 class (or a dedicated class 
for canonical extension types) instead of dereferencing.
   
   Found while bridging DuckDB's `HUGEINT`/`UHUGEINT` (exported as 
`arrow.opaque` with `arrow_lossless_conversion = true`) into R.
   
   ---
   Co-authored with Claude Code (Anthropic).
   
   ### Component(s)
   
   R
   


-- 
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