You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by pa...@apache.org on 2023/03/26 01:08:47 UTC
[arrow-nanoarrow] branch main updated: fix(r): Don't invoke undefined behaviour in conversions to/from Arrow (#167)
This is an automated email from the ASF dual-hosted git repository.
paleolimbot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-nanoarrow.git
The following commit(s) were added to refs/heads/main by this push:
new 7f5f358 fix(r): Don't invoke undefined behaviour in conversions to/from Arrow (#167)
7f5f358 is described below
commit 7f5f358cfec806ecde088f001aa8121e600bcaf4
Author: Dewey Dunnington <de...@dunnington.ca>
AuthorDate: Sat Mar 25 21:08:42 2023 -0400
fix(r): Don't invoke undefined behaviour in conversions to/from Arrow (#167)
Closes #159.
Checked via:
```bash
PKG_CFLAGS=-fsanitize=undefined PKG_LIBS=-fsanitize=undefined R CMD INSTALL . --preclean
```
Then:
```r
devtools::test()
```
---
r/src/as_array.c | 12 ++++++++++--
r/tests/testthat/test-as-array.R | 6 +++---
r/tests/testthat/test-convert-array.R | 4 ++--
3 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/r/src/as_array.c b/r/src/as_array.c
index e8eac8c..592e83b 100644
--- a/r/src/as_array.c
+++ b/r/src/as_array.c
@@ -236,7 +236,12 @@ static void as_array_dbl(SEXP x_sexp, struct ArrowArray* array, SEXP schema_xptr
int64_t* buffer_data = (int64_t*)buffer->data;
for (int64_t i = 0; i < len; i++) {
- buffer_data[i] = x_data[i];
+ // UBSAN warns for buffer_data[i] = nan
+ if (R_IsNA(x_data[i]) || R_IsNaN(x_data[i])) {
+ buffer_data[i] = 0;
+ } else {
+ buffer_data[i] = x_data[i];
+ }
}
buffer->size_bytes = len * sizeof(int64_t);
@@ -254,7 +259,10 @@ static void as_array_dbl(SEXP x_sexp, struct ArrowArray* array, SEXP schema_xptr
// It's easy to accidentally overflow here, so make sure to warn
int64_t n_overflow = 0;
for (int64_t i = 0; i < len; i++) {
- if (x_data[i] > INT_MAX || x_data[i] < INT_MIN) {
+ // UBSAN warns for buffer_data[i] = nan
+ if (R_IsNA(x_data[i]) || R_IsNaN(x_data[i])) {
+ buffer_data[i] = 0;
+ } else if (x_data[i] > INT_MAX || x_data[i] < INT_MIN) {
n_overflow++;
buffer_data[i] = 0;
} else {
diff --git a/r/tests/testthat/test-as-array.R b/r/tests/testthat/test-as-array.R
index 6beff31..fac5e65 100644
--- a/r/tests/testthat/test-as-array.R
+++ b/r/tests/testthat/test-as-array.R
@@ -163,10 +163,10 @@ test_that("as_nanoarrow_array() works for double() -> na_int32()", {
as.raw(array$buffers[[1]]),
packBits(c(rep(TRUE, 10), FALSE, rep(FALSE, 5)))
)
- # The last element here is (int)NaN not NA_integer_
+ # The last element here is 0 because (int)nan is undefined behaviour
expect_identical(
- head(as.raw(array$buffers[[2]]), 10 * 4L),
- as.raw(as_nanoarrow_buffer(1:10))
+ as.raw(array$buffers[[2]]),
+ as.raw(as_nanoarrow_buffer(c(1:10, 0L)))
)
# With overflow
diff --git a/r/tests/testthat/test-convert-array.R b/r/tests/testthat/test-convert-array.R
index 4175c10..7b982b7 100644
--- a/r/tests/testthat/test-convert-array.R
+++ b/r/tests/testthat/test-convert-array.R
@@ -329,13 +329,13 @@ test_that("convert to vector works for null -> logical()", {
})
test_that("convert to vector warns for invalid integer()", {
- array <- as_nanoarrow_array(.Machine$double.xmax)
+ array <- as_nanoarrow_array(.Machine$integer.max + 1)
expect_warning(
expect_identical(convert_array(array, integer()), NA_integer_),
"1 value\\(s\\) outside integer range set to NA"
)
- array <- as_nanoarrow_array(c(NA, .Machine$double.xmax))
+ array <- as_nanoarrow_array(c(NA, .Machine$integer.max + 1))
expect_warning(
expect_identical(convert_array(array, integer()), c(NA_integer_, NA_integer_)),
"1 value\\(s\\) outside integer range set to NA"