Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 24 additions & 4 deletions cpp/src/gandiva/gdv_function_stubs.cc
Original file line number Diff line number Diff line change
Expand Up @@ -484,7 +484,7 @@ const char* gdv_mask_first_n_utf8_int32(int64_t context, const char* data,
while ((chars_masked < n_to_mask) && (bytes_masked < data_len)) {
auto char_len =
utf8proc_iterate(reinterpret_cast<const utf8proc_uint8_t*>(data + bytes_masked),
data_len, &utf8_char);
data_len - bytes_masked, &utf8_char);

if (char_len < 0) {
gdv_fn_context_set_error_msg(context, utf8proc_errmsg(char_len));
Expand Down Expand Up @@ -592,7 +592,14 @@ const char* gdv_mask_last_n_utf8_int32(int64_t context, const char* data,
while ((bytes_read < data_len) && (chars_counter < (num_of_chars - n_to_mask))) {
auto char_len =
utf8proc_iterate(reinterpret_cast<const utf8proc_uint8_t*>(data + bytes_read),
data_len, &utf8_char);
data_len - bytes_read, &utf8_char);

if (char_len < 0) {
gdv_fn_context_set_error_msg(context, utf8proc_errmsg(char_len));
*out_len = 0;
return nullptr;
}

chars_counter++;
bytes_read += static_cast<int>(char_len);
}
Expand All @@ -606,7 +613,14 @@ const char* gdv_mask_last_n_utf8_int32(int64_t context, const char* data,
while (bytes_read < data_len) {
auto char_len =
utf8proc_iterate(reinterpret_cast<const utf8proc_uint8_t*>(data + bytes_read),
data_len, &utf8_char);
data_len - bytes_read, &utf8_char);

if (char_len < 0) {
gdv_fn_context_set_error_msg(context, utf8proc_errmsg(char_len));
*out_len = 0;
return nullptr;
}

switch (utf8proc_category(utf8_char)) {
case 1:
out[out_idx] = 'X';
Expand Down Expand Up @@ -695,7 +709,13 @@ const char* mask_utf8_utf8_utf8_utf8(int64_t context, const char* data, int32_t
while (bytes_read < data_len) {
auto char_len =
utf8proc_iterate(reinterpret_cast<const utf8proc_uint8_t*>(data + bytes_read),
data_len, &utf8_char);
data_len - bytes_read, &utf8_char);

if (char_len < 0) {
gdv_fn_context_set_error_msg(context, utf8proc_errmsg(char_len));
*out_len = 0;
return nullptr;
}
switch (utf8proc_category(utf8_char)) {
case UTF8PROC_CATEGORY_LU:
memcpy(out + out_index, upper, upper_length);
Expand Down
69 changes: 69 additions & 0 deletions cpp/src/gandiva/gdv_function_stubs_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1084,6 +1084,29 @@ TEST(TestGdvFnStubs, TestMaskFirstN) {
expected = "";
result = gdv_mask_first_n_utf8_int32(ctx_ptr, data.c_str(), data_len, 6, &out_len);
EXPECT_EQ(expected, std::string(result, out_len));

// Truncated 2-byte, 3-byte, and 4-byte UTF-8 sequences must report an error safely without OOB read
const char trunc2[] = {'a', static_cast<char>(0xC2)};
ctx.Reset();
result = gdv_mask_first_n_utf8_int32(ctx_ptr, trunc2, 2, 2, &out_len);
EXPECT_EQ(result, nullptr);
EXPECT_EQ(out_len, 0);
EXPECT_TRUE(ctx.has_error());

const char trunc3[] = {'a', static_cast<char>(0xE2), static_cast<char>(0x82)};
ctx.Reset();
result = gdv_mask_first_n_utf8_int32(ctx_ptr, trunc3, 3, 2, &out_len);
EXPECT_EQ(result, nullptr);
EXPECT_EQ(out_len, 0);
EXPECT_TRUE(ctx.has_error());

const char trunc4[] = {'a', static_cast<char>(0xF0), static_cast<char>(0x9F),
static_cast<char>(0x98)};
ctx.Reset();
result = gdv_mask_first_n_utf8_int32(ctx_ptr, trunc4, 4, 2, &out_len);
EXPECT_EQ(result, nullptr);
EXPECT_EQ(out_len, 0);
EXPECT_TRUE(ctx.has_error());
}

TEST(TestGdvFnStubs, TestMaskLastN) {
Expand Down Expand Up @@ -1149,6 +1172,29 @@ TEST(TestGdvFnStubs, TestMaskLastN) {
expected = "";
result = gdv_mask_last_n_utf8_int32(ctx_ptr, data.c_str(), data_len, 6, &out_len);
EXPECT_EQ(expected, std::string(result, out_len));

// Truncated 2-byte, 3-byte, and 4-byte UTF-8 sequences must report an error safely without OOB read
const char trunc2[] = {'a', static_cast<char>(0xC2)};
ctx.Reset();
result = gdv_mask_last_n_utf8_int32(ctx_ptr, trunc2, 2, 2, &out_len);
EXPECT_EQ(result, nullptr);
EXPECT_EQ(out_len, 0);
EXPECT_TRUE(ctx.has_error());

const char trunc3[] = {'a', static_cast<char>(0xE2), static_cast<char>(0x82)};
ctx.Reset();
result = gdv_mask_last_n_utf8_int32(ctx_ptr, trunc3, 3, 2, &out_len);
EXPECT_EQ(result, nullptr);
EXPECT_EQ(out_len, 0);
EXPECT_TRUE(ctx.has_error());

const char trunc4[] = {'a', static_cast<char>(0xF0), static_cast<char>(0x9F),
static_cast<char>(0x98)};
ctx.Reset();
result = gdv_mask_last_n_utf8_int32(ctx_ptr, trunc4, 4, 2, &out_len);
EXPECT_EQ(result, nullptr);
EXPECT_EQ(out_len, 0);
EXPECT_TRUE(ctx.has_error());
}

TEST(TestGdvFnStubs, TestTranslate) {
Expand Down Expand Up @@ -1502,6 +1548,29 @@ TEST(TestGdvFnStubs, TestMask) {
result = mask_utf8_utf8_utf8_utf8(ctx_ptr, data.c_str(), data_len, "\?", 1, "*", 1, "#",
1, &out_len);
EXPECT_EQ(std::string(result, out_len), expected);

// Truncated 2-byte, 3-byte, and 4-byte UTF-8 sequences must report an error safely without OOB read
const char trunc2[] = {'a', static_cast<char>(0xC2)};
ctx.Reset();
result = mask_utf8_utf8_utf8_utf8(ctx_ptr, trunc2, 2, "X", 1, "x", 1, "n", 1, &out_len);
EXPECT_EQ(result, nullptr);
EXPECT_EQ(out_len, 0);
EXPECT_TRUE(ctx.has_error());

const char trunc3[] = {'a', static_cast<char>(0xE2), static_cast<char>(0x82)};
ctx.Reset();
result = mask_utf8_utf8_utf8_utf8(ctx_ptr, trunc3, 3, "X", 1, "x", 1, "n", 1, &out_len);
EXPECT_EQ(result, nullptr);
EXPECT_EQ(out_len, 0);
EXPECT_TRUE(ctx.has_error());

const char trunc4[] = {'a', static_cast<char>(0xF0), static_cast<char>(0x9F),
static_cast<char>(0x98)};
ctx.Reset();
result = mask_utf8_utf8_utf8_utf8(ctx_ptr, trunc4, 4, "X", 1, "x", 1, "n", 1, &out_len);
EXPECT_EQ(result, nullptr);
EXPECT_EQ(out_len, 0);
EXPECT_TRUE(ctx.has_error());
}

TEST(TestGdvFnStubs, TestAesEncryptDecrypt16) {
Expand Down