diff --git a/cpp/src/gandiva/precompiled/time.cc b/cpp/src/gandiva/precompiled/time.cc index 2b60f63651d..9a66e41bbb1 100644 --- a/cpp/src/gandiva/precompiled/time.cc +++ b/cpp/src/gandiva/precompiled/time.cc @@ -631,7 +631,7 @@ void set_error_for_date(gdv_int32 length, const char* input, const char* msg, int64_t execution_context) { int size = length + static_cast(strlen(msg)) + 1; char* error = reinterpret_cast(malloc(size)); - snprintf(error, size, "%s%s", msg, input); + snprintf(error, size, "%s%.*s", msg, length, input); gdv_fn_context_set_error_msg(execution_context, error); free(error); } diff --git a/cpp/src/gandiva/precompiled/time_test.cc b/cpp/src/gandiva/precompiled/time_test.cc index 4310490a228..514d2e468dc 100644 --- a/cpp/src/gandiva/precompiled/time_test.cc +++ b/cpp/src/gandiva/precompiled/time_test.cc @@ -18,6 +18,8 @@ #include #include +#include + #include "arrow/util/logging_internal.h" #include "gandiva/execution_context.h" #include "gandiva/precompiled/testing.h" @@ -59,6 +61,50 @@ TEST(TestTime, TestCastDate) { EXPECT_EQ(castDATE_date32(1), 86400000); } +TEST(TestTime, TestCastDateInvalidUnterminated) { + ExecutionContext context; + int64_t context_ptr = reinterpret_cast(&context); + + // The invalid-value error message is built from the raw input pointer. Pass a + // length that stops one byte short of the trailing sentinel so the formatter + // must respect `length` rather than scanning for a NUL; without the fix the + // sentinel leaks into the error message. + const std::string input = "197201234X"; + EXPECT_EQ(castDATE_utf8(context_ptr, input.data(), + static_cast(input.length()) - 1), + 0); + EXPECT_EQ(context.get_error(), "Not a valid date value 197201234"); + context.Reset(); +} + +TEST(TestTime, TestCastTimestampInvalidUnterminated) { + ExecutionContext context; + int64_t context_ptr = reinterpret_cast(&context); + + // castTIMESTAMP_utf8 reaches the same set_error_for_date helper, so exercise + // the over-read path from that entry point too. + const std::string input = "2000-01-01 24:00:00X"; + EXPECT_EQ(castTIMESTAMP_utf8(context_ptr, input.data(), + static_cast(input.length()) - 1), + 0); + EXPECT_EQ(context.get_error(), + "Not a valid time for timestamp value 2000-01-01 24:00:00"); + context.Reset(); +} + +TEST(TestTime, TestCastTimeInvalidUnterminated) { + ExecutionContext context; + int64_t context_ptr = reinterpret_cast(&context); + + // castTIME_utf8 reaches set_error_for_date as well. + const std::string input = "24H00H00X"; + EXPECT_EQ(castTIME_utf8(context_ptr, input.data(), + static_cast(input.length()) - 1), + 0); + EXPECT_EQ(context.get_error(), "Invalid character in time 24H00H00"); + context.Reset(); +} + TEST(TestTime, TestCastTimestamp) { ExecutionContext context; int64_t context_ptr = reinterpret_cast(&context);