#615·re2

Bug: Self-move-assignment in RE2::Set and FilteredRE2 causes use-after-destroy

Author: MarkLee131Created Mar 30, 2026Updated Aug 25, 2026

Description

The move assignment operators in RE2::Set and FilteredRE2 use a destroy-then-placement-new pattern:

cpp
RE2::Set& RE2::Set::operator=(Set&& other) {
  this->~Set();
  (void) new (this) Set(std::move(other));
  return *this;
}

This is unsafe when this == &other (self-move-assignment). The destructor runs first, which calls Decref() on internal Regexp* pointers and frees resources. Then the move constructor reads from the already-destroyed object. This is undefined behavior and can lead to double-free.

Self-move-assignment can happen through aliased references. For example:

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

Affected Code

  • re2/set.cc:52-56 (RE2::Set::operator=(Set&&))
  • re2/filtered_re2.cc:45-48 (FilteredRE2::operator=(FilteredRE2&&))

I can open PR to submit a fix.