|
19 | 19 | #include <gtest/gtest.h> |
20 | 20 |
|
21 | 21 | #include <limits> |
| 22 | +#include <vector> |
22 | 23 |
|
23 | 24 | #include "gandiva/execution_context.h" |
24 | 25 | #include "gandiva/precompiled/types.h" |
@@ -1608,6 +1609,29 @@ TEST(TestStringOps, TestRpadString) { |
1608 | 1609 | EXPECT_EQ(std::string(out_str + 5000, 2), "α"); |
1609 | 1610 | } |
1610 | 1611 |
|
| 1612 | +TEST(TestStringOps, TestPadMalformedUtf8NoOverread) { |
| 1613 | + gandiva::ExecutionContext ctx; |
| 1614 | + uint64_t ctx_ptr = reinterpret_cast<gdv_int64>(&ctx); |
| 1615 | + gdv_int32 out_len = 0; |
| 1616 | + |
| 1617 | + // A 4-byte utf8 lead byte followed by non-continuation bytes and no trailing |
| 1618 | + // space. utf8_length_ignore_invalid() used to extend the glyph length past |
| 1619 | + // the end of the buffer while scanning the continuation bytes. The input is |
| 1620 | + // held in an exactly-sized heap buffer so any over-read trips AddressSanitizer. |
| 1621 | + std::vector<char> text = {'\xF0', 'a', 'a', 'a'}; |
| 1622 | + const auto text_len = static_cast<gdv_int32>(text.size()); |
| 1623 | + |
| 1624 | + const char* out_str = |
| 1625 | + lpad_utf8_int32_utf8(ctx_ptr, text.data(), text_len, 6, " ", 1, &out_len); |
| 1626 | + EXPECT_EQ(out_len, 9); |
| 1627 | + EXPECT_EQ(std::string(out_str + out_len - text_len, text_len), |
| 1628 | + std::string(text.begin(), text.end())); |
| 1629 | + |
| 1630 | + out_str = rpad_utf8_int32_utf8(ctx_ptr, text.data(), text_len, 6, " ", 1, &out_len); |
| 1631 | + EXPECT_EQ(out_len, 9); |
| 1632 | + EXPECT_EQ(std::string(out_str, text_len), std::string(text.begin(), text.end())); |
| 1633 | +} |
| 1634 | + |
1611 | 1635 | TEST(TestStringOps, TestRtrim) { |
1612 | 1636 | gandiva::ExecutionContext ctx; |
1613 | 1637 | uint64_t ctx_ptr = reinterpret_cast<gdv_int64>(&ctx); |
|
0 commit comments