Fix From_base64 bugs

This commit is contained in:
obdev
2022-12-13 08:38:03 +00:00
committed by ob-robot
parent a468628f8e
commit c1de0db3a8
6 changed files with 60 additions and 50 deletions

View File

@ -158,8 +158,24 @@ int ObBase64Encoder::decode(const char *input, const int64_t input_len,
int64_t &pos, bool skip_spaces)
{
int ret = OB_SUCCESS;
if (OB_ISNULL(input) || OB_ISNULL(output) ||
OB_UNLIKELY(input_len < 0 || output_len < 0 || pos< 0)) {
bool all_skipped = false;
if (OB_ISNULL(input) || OB_UNLIKELY(input_len < 0 || output_len < 0 || pos< 0)) {
ret = OB_INVALID_ARGUMENT;
_OB_LOG(WARN, "invalid argument input=%p, output=%p, input_len=%ld, output_len=%ld, pos=%ld",
input, output, input_len, output_len, pos);
} else if (skip_spaces) {
all_skipped = true;
for (int64_t i = 0; all_skipped && i < input_len; ++i) {
if (!ObBase64Encoder::my_base64_decoder_skip_spaces(input[i])) {
all_skipped = false;
}
}
}
if (OB_FAIL(ret)) {
} else if (all_skipped) {
//return empty string
pos = 0;
} else if (OB_ISNULL(output)) {
ret = OB_INVALID_ARGUMENT;
_OB_LOG(WARN, "invalid argument input=%p, output=%p, input_len=%ld, output_len=%ld, pos=%ld",
input, output, input_len, output_len, pos);
@ -177,10 +193,8 @@ int ObBase64Encoder::decode(const char *input, const int64_t input_len,
int64_t skipped_spaces = 0;
for(; OB_SUCC(ret) && iter_input < (input + input_len) && '=' != *iter_input; iter_input++) {
if (OB_UNLIKELY(!is_base64_char(*iter_input))) {
if (skip_spaces) {
if (my_base64_decoder_skip_spaces(*iter_input)) {
++skipped_spaces;
}
if (skip_spaces && my_base64_decoder_skip_spaces(*iter_input)) {
++skipped_spaces;
} else {
ret = OB_INVALID_ARGUMENT;
_OB_LOG(WARN, "invalid base64 char, cur_idx=%ld, char=%c",
@ -204,27 +218,28 @@ int ObBase64Encoder::decode(const char *input, const int64_t input_len,
}
} // for end
int64_t cur_idx = iter_input - input;
for (const char *iter = iter_input; iter < input + input_len; iter++) {
if (skip_spaces) {
if (my_base64_decoder_skip_spaces(*iter)) {
++skipped_spaces;
}
} else {
// all the rest chars must be '='
if (OB_UNLIKELY('=' != *iter)) {
ret = OB_INVALID_ARGUMENT;
}
int64_t cur_valid_len = iter_input - input - skipped_spaces;
for (const char *iter = iter_input; OB_SUCC(ret) && iter < input + input_len; iter++) {
// all the rest chars must be '='
if (skip_spaces && my_base64_decoder_skip_spaces(*iter)) {
skipped_spaces++;
} else if (OB_UNLIKELY('=' != *iter)) {
ret = OB_INVALID_ARGUMENT;
}
}// end for
if (skip_spaces) {
if (OB_FAIL(ret)) {
} else if (!skip_spaces) {
if (OB_UNLIKELY((cur_idx + 3 <= input_len))) {
// only last char or last two chars can be '='
ret = OB_INVALID_ARGUMENT;
}
} else {
int64_t valid_len = input_len - skipped_spaces;
if (valid_len % 4 != 0 || valid_len < 4 || cur_idx + 3 <= valid_len) {
if (valid_len % 4 != 0 || cur_valid_len + 3 <= valid_len) {
ret = OB_INVALID_ARGUMENT;
}
}
if (OB_UNLIKELY((cur_idx + 3 <= input_len) && !skip_spaces)) {
// only last char or last two chars can be '='
ret = OB_INVALID_ARGUMENT;
if (OB_FAIL(ret)) {
} else if (i > 0) {
for (int k = 0; k < i; k++) {
uint8_array_4[k] = BASE64_VALUES[uint8_array_4[k]];

View File

@ -35,14 +35,6 @@ static int FROM_BASE64_TABLE[];
return std::isalnum(c) || c == '+' || c == '/';
}
static inline bool my_base64_decoder_skip_spaces(char c)
{
if (FROM_BASE64_TABLE[(uint8_t) c] != -2) {
return false;
}
return true;
}
static const int64_t SOFT_NEW_LINE_STR_POS = 19;
public:
static constexpr int64_t needed_encoded_length(const int64_t buf_size)
@ -55,6 +47,15 @@ public:
return (buf_size / 4) * 3;
}
static inline bool my_base64_decoder_skip_spaces(char c)
{
if (FROM_BASE64_TABLE[(uint8_t) c] != -2) {
return false;
}
return true;
}
static int encode(const uint8_t* input, const int64_t input_len,
char* output, const int64_t output_len,
int64_t &pos, const int16_t wrap = 0);

View File

@ -27,7 +27,7 @@ namespace sql
{
ObExprFromBase64::ObExprFromBase64(ObIAllocator &alloc)
:ObFuncExprOperator(alloc, T_FUN_SYS_FROM_BASE64, N_FROM_BASE64, 1, NOT_ROW_DIMENSION)
:ObStringExprOperator(alloc, T_FUN_SYS_FROM_BASE64, N_FROM_BASE64, 1)
{
}
@ -126,21 +126,18 @@ int ObExprFromBase64::eval_from_base64(const ObExpr &expr,
} else {
const ObString & in_raw = arg->get_string();
ObLength in_raw_len = in_raw.length();
if (OB_UNLIKELY(in_raw_len == 0)) {
const char *buf = in_raw.ptr();
if (NULL == buf) {
res.set_string(nullptr, 0);
} else {
const char *buf = in_raw.ptr();
char *output_buf = nullptr;
char *output_buf = NULL;
int64_t buf_len = base64_needed_decoded_length(in_raw_len);
int64_t pos = 0;
ObEvalCtx::TempAllocGuard alloc_guard(ctx);
output_buf = static_cast<char*>(alloc_guard.get_allocator().alloc(buf_len));
if (OB_ISNULL(output_buf)) {
LOG_WARN("output_buf is null", K(ret), K(buf_len), K(in_raw_len));
res.set_null();
} else if (OB_FAIL(ObBase64Encoder::decode(buf, in_raw_len,
reinterpret_cast<uint8_t*>(output_buf),
buf_len, pos, true))) {
if (OB_FAIL(ObBase64Encoder::decode(buf, in_raw_len,
reinterpret_cast<uint8_t*>(output_buf),
buf_len, pos, true))) {
if (OB_UNLIKELY(ret == OB_INVALID_ARGUMENT)) {
ret = OB_SUCCESS;
res.set_null();
@ -181,20 +178,17 @@ int ObExprFromBase64::eval_from_base64_batch(const ObExpr &expr, ObEvalCtx &ctx,
ObDatum *arg = args.at(j);
const ObString & in_raw = arg->get_string();
ObLength in_raw_len = in_raw.length();
if (OB_UNLIKELY(in_raw_len == 0)) {
const char *buf = in_raw.ptr();
if (NULL == buf) {
res[j].set_string(nullptr, 0);
} else {
const char *buf = in_raw.ptr();
char *output_buf = nullptr;
int64_t buf_len = base64_needed_decoded_length(in_raw_len);
int64_t pos = 0;
output_buf = static_cast<char*>(alloc_guard.get_allocator().alloc(buf_len));
if (OB_ISNULL(output_buf)) {
LOG_WARN("output_buf is null", K(ret), K(buf_len), K(in_raw_len));
res[j].set_null();
} else if (OB_FAIL(ObBase64Encoder::decode(buf, in_raw_len,
reinterpret_cast<uint8_t*>(output_buf),
buf_len, pos, true))) {
if (OB_FAIL(ObBase64Encoder::decode(buf, in_raw_len,
reinterpret_cast<uint8_t*>(output_buf),
buf_len, pos, true))) {
if (OB_UNLIKELY(ret == OB_INVALID_ARGUMENT)) {
ret = OB_SUCCESS;
res[j].set_null();

View File

@ -20,7 +20,7 @@ namespace oceanbase
{
namespace sql
{
class ObExprFromBase64 : public ObFuncExprOperator {
class ObExprFromBase64 : public ObStringExprOperator {
public:
explicit ObExprFromBase64(common::ObIAllocator &alloc);
virtual ~ObExprFromBase64();

View File

@ -27,7 +27,7 @@ namespace sql
{
ObExprToBase64::ObExprToBase64(ObIAllocator &alloc)
:ObFuncExprOperator(alloc, T_FUN_SYS_TO_BASE64, N_TO_BASE64, 1, NOT_ROW_DIMENSION)
:ObStringExprOperator(alloc, T_FUN_SYS_TO_BASE64, N_TO_BASE64, 1)
{
}

View File

@ -20,7 +20,7 @@ namespace oceanbase
{
namespace sql
{
class ObExprToBase64 : public ObFuncExprOperator
class ObExprToBase64 : public ObStringExprOperator
{
public:
explicit ObExprToBase64(common::ObIAllocator &alloc);