Skip to content

Commit ff6df56

Browse files
author
Tor Didriksen
committed
Bug #32050219 REGEXP_ENGINE::REPLACE DOESN'T RESET ERROR CODE AFTER PROCESSING A RECORD
Regexp_engine::Reset() failed to initialize the status variable m_error_code. This could lead to an internal ICU warning generated for one row "spilling" over to the processing of subsequent rows. In Regexp_engine::Replace(), test for U_SUCCESS rather than U_ZERO_ERROR, i.e. ignore warnings for the 'not found' case. Add unittest to verify that warnings are reset between regexp engine executions. Change-Id: Ifdf70c33976228e86c0393d90a88da037ac595db
1 parent 9478e87 commit ff6df56

File tree

4 files changed

+29
-3
lines changed

4 files changed

+29
-3
lines changed

sql/regexp/regexp_engine.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2017, 2020, Oracle and/or its affiliates.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License, version 2.0,
@@ -41,6 +41,7 @@ UBool QueryNotKilled(const void *thd, int32_t) {
4141
const char *icu_version_string() { return U_ICU_VERSION; }
4242

4343
void Regexp_engine::Reset(const std::u16string &subject) {
44+
m_error_code = U_ZERO_ERROR;
4445
auto usubject = subject.data();
4546
int length = subject.size();
4647
uregex_setText(m_re, pointer_cast<const UChar *>(usubject), length,
@@ -82,7 +83,7 @@ const std::u16string &Regexp_engine::Replace(const std::u16string &replacement,
8283
call to uregex_appendReplacement() leads to ICU trying to free the buffer
8384
that we own, thus causing a double-delete.
8485
*/
85-
if (!found && m_error_code == U_ZERO_ERROR) return m_current_subject;
86+
if (!found && U_SUCCESS(m_error_code)) return m_current_subject;
8687

8788
m_replace_buffer.resize(std::min(m_current_subject.size(), HardLimit()));
8889

sql/regexp/regexp_engine.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#ifndef SQL_REGEXP_REGEXP_ENGINE_H_
22
#define SQL_REGEXP_REGEXP_ENGINE_H_
33

4-
/* Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
4+
/* Copyright (c) 2017, 2020, Oracle and/or its affiliates.
55
66
This program is free software; you can redistribute it and/or modify
77
it under the terms of the GNU General Public License, version 2.0,
@@ -176,6 +176,9 @@ class Regexp_engine {
176176
*/
177177
std::pair<int, int> MatchedSubstring();
178178

179+
bool HasWarning() const {
180+
return U_SUCCESS(m_error_code) && m_error_code != U_ZERO_ERROR;
181+
}
179182
bool IsError() const { return U_FAILURE(m_error_code); }
180183
bool CheckError() const { return check_icu_status(m_error_code); }
181184

sql/regexp/regexp_facade.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,11 @@ class Regexp_facade {
125125
/// Delete the "engine" data structure after execution.
126126
void cleanup() { m_engine = nullptr; }
127127

128+
/// Did any operation return a warning? For unit testing.
129+
bool EngineHasWarning() const {
130+
return m_engine != nullptr && m_engine->HasWarning();
131+
}
132+
128133
private:
129134
/**
130135
Resets the compiled regular expression with a new string.

unittest/gunit/regexp_facade-t.cc

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,4 +124,21 @@ TEST_F(RegexpFacadeTest, SetPattern) {
124124
regex.SetPattern(nullptr, 0);
125125
}
126126

127+
TEST_F(RegexpFacadeTest, Replace) {
128+
StringBuffer<STRING_BUFFER_USUAL_SIZE> buf;
129+
Item *subject1 = make_fixed_literal(thd(), " aaa");
130+
Item *subject2 = make_fixed_literal(thd(), "");
131+
Item *replacement = make_fixed_literal(thd(), "aamz");
132+
const char *pattern = " +";
133+
MockRegexpFacade regex(thd(), pattern);
134+
135+
regex.Replace(subject1, replacement, 1, 0, &buf);
136+
// These arguments to Replace() will set U_STRING_NOT_TERMINATED_WARNING.
137+
EXPECT_TRUE(regex.EngineHasWarning());
138+
139+
regex.Replace(subject2, replacement, 1, 0, &buf);
140+
// The previous warning should have been cleared.
141+
EXPECT_FALSE(regex.EngineHasWarning());
142+
}
143+
127144
} // namespace regexp_facade_unittest

0 commit comments

Comments
 (0)