From 7e0e982ec03da502d1fc2b0b7b435416ff1a0d44 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Thu, 22 Oct 2026 17:11:29 +0200 Subject: [PATCH 1/2] GH-54936: [C++] Ensure reading an invalid map array from IPC doesn't crash --- cpp/src/arrow/ipc/reader.cc | 16 ++++++++++++++++ testing | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/cpp/src/arrow/ipc/reader.cc b/cpp/src/arrow/ipc/reader.cc index 4c10686b19b9..fae83c6a27ea 100644 --- a/cpp/src/arrow/ipc/reader.cc +++ b/cpp/src/arrow/ipc/reader.cc @@ -34,6 +34,7 @@ #include // IWYU pragma: export #include "arrow/array.h" +#include "arrow/array/validate.h" #include "arrow/buffer.h" #include "arrow/extension_type.h" #include "arrow/io/caching.h" @@ -455,6 +456,21 @@ class ArrayLoader { Status Visit(const MapType& type) { RETURN_NOT_OK(LoadList(type)); + if (!out_->child_data.empty()) { + // Ensure that GetNullCount() calls in MapArray::ValidateChildData + // don't access invalid memory. + // We cannot call array validation as it will fail on non-native endianness + // (due to checking the last offset on variable-width data) or missing + // dictionaries (they are not yet populated at this point). + const ArrayData& child_data = *out_->child_data[0]; + if (child_data.null_count != 0) { + return Status::Invalid("Map array child array should have no nulls"); + } + if (!child_data.child_data.empty() && child_data.child_data[0]->null_count != 0) { + return Status::Invalid("Map array keys array should have no nulls"); + } + } + // If we don't do this, MapArray::SetData will abort on invalid data. return MapArray::ValidateChildData(out_->child_data); } diff --git a/testing b/testing index 9ff285c88565..5a26d35785ff 160000 --- a/testing +++ b/testing @@ -1 +1 @@ -Subproject commit 9ff285c88565f0f6abc855918c6a342e70e4909c +Subproject commit 5a26d35785ff8761e56d79eebff971f6f737e18c From 91bd53106cfef78cd9a18a6105b95569f8b505d8 Mon Sep 17 00:00:00 2001 From: Antoine Pitrou Date: Thu, 29 Oct 2026 10:44:48 +0100 Subject: [PATCH 2/2] Address review comments --- cpp/src/arrow/ipc/reader.cc | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/cpp/src/arrow/ipc/reader.cc b/cpp/src/arrow/ipc/reader.cc index fae83c6a27ea..25a877833065 100644 --- a/cpp/src/arrow/ipc/reader.cc +++ b/cpp/src/arrow/ipc/reader.cc @@ -456,19 +456,18 @@ class ArrayLoader { Status Visit(const MapType& type) { RETURN_NOT_OK(LoadList(type)); - if (!out_->child_data.empty()) { - // Ensure that GetNullCount() calls in MapArray::ValidateChildData - // don't access invalid memory. - // We cannot call array validation as it will fail on non-native endianness - // (due to checking the last offset on variable-width data) or missing - // dictionaries (they are not yet populated at this point). - const ArrayData& child_data = *out_->child_data[0]; - if (child_data.null_count != 0) { - return Status::Invalid("Map array child array should have no nulls"); - } - if (!child_data.child_data.empty() && child_data.child_data[0]->null_count != 0) { - return Status::Invalid("Map array keys array should have no nulls"); - } + DCHECK_EQ(out_->child_data.size(), 1); // ensured by LoadList() + // Ensure that GetNullCount() calls in MapArray::ValidateChildData + // don't access invalid memory. + // We cannot call array validation as it will fail on non-native endianness + // (due to checking the last offset on variable-width data) or missing + // dictionaries (they are not yet populated at this point). + const ArrayData& child_data = *out_->child_data[0]; + if (child_data.null_count != 0) { + return Status::Invalid("Map array child array should have no nulls"); + } + if (!child_data.child_data.empty() && child_data.child_data[0]->null_count != 0) { + return Status::Invalid("Map array keys array should have no nulls"); } // If we don't do this, MapArray::SetData will abort on invalid data. return MapArray::ValidateChildData(out_->child_data);