Skip to content

Fix self-move-assignment UB in RE2::Set and FilteredRE2, add missing compiled_ guards#637

Open
XananasX7 wants to merge 4 commits into
google:mainfrom
XananasX7:fix/self-move-assignment-uaf
Open

Fix self-move-assignment UB in RE2::Set and FilteredRE2, add missing compiled_ guards#637
XananasX7 wants to merge 4 commits into
google:mainfrom
XananasX7:fix/self-move-assignment-uaf

Conversation

@XananasX7
Copy link
Copy Markdown

Summary

This PR fixes two classes of undefined behavior in RE2::Set and FilteredRE2:

Fix 1: Self-move-assignment undefined behavior (UB) in RE2::Set and FilteredRE2

Files: re2/set.cc, re2/filtered_re2.cc

The move assignment operators in both classes use a destroy-then-placement-new pattern:

RE2::Set& RE2::Set::operator=(Set&& other) {
  this->~Set();                        // destroys *this first
  (void) new (this) Set(std::move(other)); // then move-constructs from other
  return *this;
}

This is undefined behavior when this == &other (self-move-assignment). The destructor runs first, calling Decref() on internal Regexp* pointers and freeing resources. The subsequent move constructor then reads from the already-destroyed object — a use-after-free leading to potential double-free and heap corruption.

Self-move-assignment can occur through aliased references, for example:

std::vector<RE2::Set> v = ...;
v[i] = std::move(v[j]);  // undefined behavior if i == j

Fix: Add a self-assignment guard (if (this != &other)) before the destroy-and-reconstruct sequence, matching the standard idiomatic fix for this pattern.

Fix 2: Missing compiled_ guard in FilteredRE2::AllMatches() and FilteredRE2::AllPotentials()

File: re2/filtered_re2.cc

FilteredRE2::FirstMatch() correctly checks the compiled_ flag (line 100) and returns early with a DFATAL log if Compile() was not called. However, AllMatches() and AllPotentials() lack this guard entirely.

Calling either function before Compile() results in undefined behavior because the prefilter_tree_ has not been built — the same class of crash previously fixed for Filter.Match() in the Python bindings (issue #484).

Fix: Add identical compiled_ guards to AllMatches() and AllPotentials(), consistent with FirstMatch().


Both fixes are minimal, targeted, and follow the existing style of the codebase.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant