-
Notifications
You must be signed in to change notification settings - Fork 4.2k
GH-50440: [C++][Gandiva] fix out-of-bounds read in set_error_for_date #50441
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,6 +18,8 @@ | |
| #include <gmock/gmock.h> | ||
| #include <gtest/gtest.h> | ||
|
|
||
| #include <string> | ||
|
|
||
| #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<int64_t>(&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"; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we keep the exactly-sized, non-NUL-terminated buffer here and in the timestamp/time tests? With Please restore the exactly-sized unterminated buffers from the previous commit, or use an equivalent guarded allocation, for all three entry points. p.s. In general it's a good local development practice to stash all fixes and just run the new tests to see how they behave - with agentic coding I started to use that approach again on pretty much everything I code ¯_(ツ)_/¯ |
||
| EXPECT_EQ(castDATE_utf8(context_ptr, input.data(), | ||
| static_cast<int32_t>(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<int64_t>(&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<int32_t>(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<int64_t>(&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<int32_t>(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<int64_t>(&context); | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It appears that time and timestamp are going through the same code path. Is this so?
If yes, would there be value in adding two more tests for those data types?
p.s. rest of PR looks good to me just need an evaluation of value of additional tests as helper isn't really data type specific.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, both castTIMESTAMP_utf8 and castTIME_utf8 hit the same set_error_for_date helper, so the fix already covers them. Added a test for each anyway (2000-01-01 24:00:00 for timestamp, 24H00H00 for time) so the over-read path is exercised from all three entry points with an unterminated buffer.