This is an automated email from the ASF dual-hosted git repository.
kou pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/main by this push:
new d0919579cb GH-50075: [C++][Gandiva] fix buffer overrun in to_hex
int32/int64 (#50076)
d0919579cb is described below
commit d0919579cbdd37549ba163c0d61843f04bac92cd
Author: metsw24-max <[email protected]>
AuthorDate: Fri Jun 26 06:32:26 2026 +0530
GH-50075: [C++][Gandiva] fix buffer overrun in to_hex int32/int64 (#50076)
### Rationale for this change
`to_hex_int64` and `to_hex_int32` in
`cpp/src/gandiva/precompiled/string_ops.cc` allocate the arena buffer with the
bare hex-digit count (16 and 8 bytes) but pass that size + 1 as the `snprintf`
bound. For any full-width value (`to_hex(-1::bigint)` -> `FFFFFFFFFFFFFFFF`,
`INT64_MIN`, `INT32_MIN`, ...) `snprintf` writes all digits plus the trailing
NUL, one byte past the end of the allocation. `gdv_fn_context_arena_malloc`
returns exactly the requested bytes, so the NUL corrupts the ad [...]
### What changes are included in this PR?
Allocate one extra byte in both functions so the allocation matches the
`snprintf` bound, the same fix as GH-49752 applied to the identical pattern in
`hash_utils.cc`.
### Are these changes tested?
Yes. The existing `TestToHexInt64` / `TestToHexInt32` cases already
exercise the full-width path (`INT64_MIN`, `INT32_MIN`, -1) and run clean under
ASAN with this change. Output behaviour is unchanged.
### Are there any user-facing changes?
No.
**This PR contains a "Critical Fix".** It fixes a one-byte out-of-bounds
heap write reachable from the `to_hex` Gandiva functions over untrusted input.
* GitHub Issue: #50075
Authored-by: metsw24-max <[email protected]>
Signed-off-by: Sutou Kouhei <[email protected]>
---
cpp/src/gandiva/precompiled/string_ops.cc | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/cpp/src/gandiva/precompiled/string_ops.cc
b/cpp/src/gandiva/precompiled/string_ops.cc
index 8dc941e28c..0dd02cb1d8 100644
--- a/cpp/src/gandiva/precompiled/string_ops.cc
+++ b/cpp/src/gandiva/precompiled/string_ops.cc
@@ -2895,8 +2895,9 @@ const char* to_hex_binary(int64_t context, const char*
text, int32_t text_len,
FORCE_INLINE
const char* to_hex_int64(int64_t context, int64_t data, int32_t* out_len) {
const int64_t hex_long_max_size = 2 * sizeof(int64_t);
- auto ret =
- reinterpret_cast<char*>(gdv_fn_context_arena_malloc(context,
hex_long_max_size));
+ // Allocate one extra byte for the null terminator written by snprintf.
+ auto ret = reinterpret_cast<char*>(
+ gdv_fn_context_arena_malloc(context, hex_long_max_size + 1));
if (ret == nullptr) {
gdv_fn_context_set_error_msg(context, "Could not allocate memory for
output string");
@@ -2912,7 +2913,8 @@ const char* to_hex_int64(int64_t context, int64_t data,
int32_t* out_len) {
FORCE_INLINE
const char* to_hex_int32(int64_t context, int32_t data, int32_t* out_len) {
const int32_t max_size = 2 * sizeof(int32_t);
- auto ret = reinterpret_cast<char*>(gdv_fn_context_arena_malloc(context,
max_size));
+ // Allocate one extra byte for the null terminator written by snprintf.
+ auto ret = reinterpret_cast<char*>(gdv_fn_context_arena_malloc(context,
max_size + 1));
if (ret == nullptr) {
gdv_fn_context_set_error_msg(context, "Could not allocate memory for
output string");