This is an automated email from the ASF dual-hosted git repository.

agrove pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion-comet.git


The following commit(s) were added to refs/heads/main by this push:
     new 1772097ae feat: enable debug assertions in CI profile, fix unaligned 
memory access bug (#3652)
1772097ae is described below

commit 1772097ae57e936f2e17e1614796c8b524c4da51
Author: Andy Grove <[email protected]>
AuthorDate: Mon Mar 9 19:54:29 2026 -0600

    feat: enable debug assertions in CI profile, fix unaligned memory access 
bug (#3652)
---
 .github/workflows/iceberg_spark_test.yml           |  1 +
 .github/workflows/pr_benchmark_check.yml           |  1 +
 .github/workflows/pr_build_linux.yml               |  1 +
 .github/workflows/pr_build_macos.yml               |  1 +
 .github/workflows/spark_sql_test.yml               |  1 +
 .../workflows/spark_sql_test_native_datafusion.yml |  1 +
 .../spark_sql_test_native_iceberg_compat.yml       |  1 +
 native/Cargo.toml                                  |  2 ++
 native/core/src/errors.rs                          |  5 +++-
 native/core/src/execution/jni_api.rs               | 28 ++++++++++++++++++----
 .../src/execution/shuffle/spark_unsafe/list.rs     |  2 +-
 .../core/src/execution/shuffle/spark_unsafe/row.rs |  7 +++---
 12 files changed, 41 insertions(+), 10 deletions(-)

diff --git a/.github/workflows/iceberg_spark_test.yml 
b/.github/workflows/iceberg_spark_test.yml
index eae828107..ec764279a 100644
--- a/.github/workflows/iceberg_spark_test.yml
+++ b/.github/workflows/iceberg_spark_test.yml
@@ -48,6 +48,7 @@ on:
 
 env:
   RUST_VERSION: stable
+  RUST_BACKTRACE: 1
 
 jobs:
   # Build native library once and share with all test jobs
diff --git a/.github/workflows/pr_benchmark_check.yml 
b/.github/workflows/pr_benchmark_check.yml
index f3af4d781..6376a3548 100644
--- a/.github/workflows/pr_benchmark_check.yml
+++ b/.github/workflows/pr_benchmark_check.yml
@@ -41,6 +41,7 @@ on:
 
 env:
   RUST_VERSION: stable
+  RUST_BACKTRACE: 1
 
 jobs:
   benchmark-check:
diff --git a/.github/workflows/pr_build_linux.yml 
b/.github/workflows/pr_build_linux.yml
index 0c7d3fc3e..dfb63a880 100644
--- a/.github/workflows/pr_build_linux.yml
+++ b/.github/workflows/pr_build_linux.yml
@@ -48,6 +48,7 @@ on:
 
 env:
   RUST_VERSION: stable
+  RUST_BACKTRACE: 1
 
 jobs:
 
diff --git a/.github/workflows/pr_build_macos.yml 
b/.github/workflows/pr_build_macos.yml
index fb4dfa975..7a57b6334 100644
--- a/.github/workflows/pr_build_macos.yml
+++ b/.github/workflows/pr_build_macos.yml
@@ -48,6 +48,7 @@ on:
 
 env:
   RUST_VERSION: stable
+  RUST_BACKTRACE: 1
 
 jobs:
 
diff --git a/.github/workflows/spark_sql_test.yml 
b/.github/workflows/spark_sql_test.yml
index 91632d04d..4d777cda8 100644
--- a/.github/workflows/spark_sql_test.yml
+++ b/.github/workflows/spark_sql_test.yml
@@ -54,6 +54,7 @@ on:
 
 env:
   RUST_VERSION: stable
+  RUST_BACKTRACE: 1
 
 jobs:
 
diff --git a/.github/workflows/spark_sql_test_native_datafusion.yml 
b/.github/workflows/spark_sql_test_native_datafusion.yml
index d5165a378..8df9d4801 100644
--- a/.github/workflows/spark_sql_test_native_datafusion.yml
+++ b/.github/workflows/spark_sql_test_native_datafusion.yml
@@ -28,6 +28,7 @@ on:
 
 env:
   RUST_VERSION: stable
+  RUST_BACKTRACE: 1
 
 jobs:
   spark-sql-catalyst-native-datafusion:
diff --git a/.github/workflows/spark_sql_test_native_iceberg_compat.yml 
b/.github/workflows/spark_sql_test_native_iceberg_compat.yml
index 100460385..af84e8556 100644
--- a/.github/workflows/spark_sql_test_native_iceberg_compat.yml
+++ b/.github/workflows/spark_sql_test_native_iceberg_compat.yml
@@ -28,6 +28,7 @@ on:
 
 env:
   RUST_VERSION: stable
+  RUST_BACKTRACE: 1
 
 jobs:
   spark-sql-catalyst-native-iceberg-compat:
diff --git a/native/Cargo.toml b/native/Cargo.toml
index 7e0f9d884..7979978a3 100644
--- a/native/Cargo.toml
+++ b/native/Cargo.toml
@@ -71,4 +71,6 @@ strip = "debuginfo"
 inherits = "release"
 lto = false          # Skip LTO for faster linking
 codegen-units = 16   # Parallel codegen (faster compile, slightly larger 
binary)
+debug-assertions = true
+panic = "unwind"     # Allow panics to be caught and logged across FFI boundary
 # overflow-checks inherited as false from release
diff --git a/native/core/src/errors.rs b/native/core/src/errors.rs
index 1329614cd..7c8957dba 100644
--- a/native/core/src/errors.rs
+++ b/native/core/src/errors.rs
@@ -145,7 +145,10 @@ pub enum CometError {
 }
 
 pub fn init() {
-    std::panic::set_hook(Box::new(|_panic_info| {
+    std::panic::set_hook(Box::new(|panic_info| {
+        // Log the panic message and location to stderr so it is visible in CI 
logs
+        // even if the exception message is lost crossing the FFI boundary
+        eprintln!("Comet native panic: {panic_info}");
         // Capture the backtrace for a panic
         *PANIC_BACKTRACE.lock().unwrap() =
             Some(std::backtrace::Backtrace::force_capture().to_string());
diff --git a/native/core/src/execution/jni_api.rs 
b/native/core/src/execution/jni_api.rs
index 1030e30aa..f5931b7dc 100644
--- a/native/core/src/execution/jni_api.rs
+++ b/native/core/src/execution/jni_api.rs
@@ -29,7 +29,7 @@ use crate::{
 use arrow::array::{Array, RecordBatch, UInt32Array};
 use arrow::compute::{take, TakeOptions};
 use arrow::datatypes::DataType as ArrowDataType;
-use datafusion::common::{Result as DataFusionResult, ScalarValue};
+use datafusion::common::{DataFusionError, Result as DataFusionResult, 
ScalarValue};
 use datafusion::execution::disk_manager::DiskManagerMode;
 use datafusion::execution::memory_pool::MemoryPool;
 use datafusion::execution::runtime_env::RuntimeEnvBuilder;
@@ -59,6 +59,7 @@ use datafusion_spark::function::string::concat::SparkConcat;
 use datafusion_spark::function::string::space::SparkSpace;
 use futures::poll;
 use futures::stream::StreamExt;
+use futures::FutureExt;
 use jni::objects::JByteBuffer;
 use jni::sys::{jlongArray, JNI_FALSE};
 use jni::{
@@ -570,10 +571,29 @@ pub unsafe extern "system" fn 
Java_org_apache_comet_Native_executePlan(
                     let (tx, rx) = mpsc::channel(2);
                     let mut stream = stream;
                     get_runtime().spawn(async move {
-                        while let Some(batch) = stream.next().await {
-                            if tx.send(batch).await.is_err() {
-                                break;
+                        let result = std::panic::AssertUnwindSafe(async {
+                            while let Some(batch) = stream.next().await {
+                                if tx.send(batch).await.is_err() {
+                                    break;
+                                }
                             }
+                        })
+                        .catch_unwind()
+                        .await;
+
+                        if let Err(panic) = result {
+                            let msg = match panic.downcast_ref::<&str>() {
+                                Some(s) => s.to_string(),
+                                None => match panic.downcast_ref::<String>() {
+                                    Some(s) => s.clone(),
+                                    None => "unknown panic".to_string(),
+                                },
+                            };
+                            let _ = tx
+                                .send(Err(DataFusionError::Execution(format!(
+                                    "native panic: {msg}"
+                                ))))
+                                .await;
                         }
                     });
                     exec_context.batch_receiver = Some(rx);
diff --git a/native/core/src/execution/shuffle/spark_unsafe/list.rs 
b/native/core/src/execution/shuffle/spark_unsafe/list.rs
index cc7281394..259ff29a7 100644
--- a/native/core/src/execution/shuffle/spark_unsafe/list.rs
+++ b/native/core/src/execution/shuffle/spark_unsafe/list.rs
@@ -90,7 +90,7 @@ impl SparkUnsafeArray {
         unsafe {
             let mask: i64 = 1i64 << (index & 0x3f);
             let word_offset = (self.row_addr + 8 + (((index >> 6) as i64) << 
3)) as *const i64;
-            let word: i64 = *word_offset;
+            let word: i64 = word_offset.read_unaligned();
             (word & mask) != 0
         }
     }
diff --git a/native/core/src/execution/shuffle/spark_unsafe/row.rs 
b/native/core/src/execution/shuffle/spark_unsafe/row.rs
index 02daf6a34..fe80d56d9 100644
--- a/native/core/src/execution/shuffle/spark_unsafe/row.rs
+++ b/native/core/src/execution/shuffle/spark_unsafe/row.rs
@@ -290,7 +290,7 @@ impl SparkUnsafeRow {
         unsafe {
             let mask: i64 = 1i64 << (index & 0x3f);
             let word_offset = (self.row_addr + (((index >> 6) as i64) << 3)) 
as *const i64;
-            let word: i64 = *word_offset;
+            let word: i64 = word_offset.read_unaligned();
             (word & mask) != 0
         }
     }
@@ -303,8 +303,8 @@ impl SparkUnsafeRow {
         unsafe {
             let mask: i64 = 1i64 << (index & 0x3f);
             let word_offset = (self.row_addr + (((index >> 6) as i64) << 3)) 
as *mut i64;
-            let word: i64 = *word_offset;
-            *word_offset = word & !mask;
+            let word: i64 = word_offset.read_unaligned();
+            word_offset.write_unaligned(word & !mask);
         }
     }
 }
@@ -968,7 +968,6 @@ mod test {
     }
 
     #[test]
-    #[cfg_attr(miri, ignore)] // Unaligned memory access in SparkUnsafeRow
     fn test_append_null_struct_field_to_struct_builder() {
         let data_type = DataType::Struct(Fields::from(vec![
             Field::new("a", DataType::Boolean, true),


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to