Skip to content
Open
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
15 changes: 10 additions & 5 deletions re2/compile.cc
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@
#include <string.h>

#include <string>
#include <unordered_map>
#include <utility>

#include "absl/container/flat_hash_map.h"
#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
#include "absl/strings/string_view.h"
Expand Down Expand Up @@ -215,7 +215,7 @@ class Compiler : public Regexp::Walker<Frag> {

int64_t max_mem_; // Total memory budget.

absl::flat_hash_map<uint64_t, int> rune_cache_;
std::unordered_map<uint64_t, int> rune_cache_;
Frag rune_range_;

RE2::Anchor anchor_; // anchor mode for RE2::Set
Expand Down Expand Up @@ -482,9 +482,12 @@ static uint64_t MakeRuneCacheKey(uint8_t lo, uint8_t hi, bool foldcase,
int Compiler::CachedRuneByteSuffix(uint8_t lo, uint8_t hi, bool foldcase,
int next) {
uint64_t key = MakeRuneCacheKey(lo, hi, foldcase, next);
absl::flat_hash_map<uint64_t, int>::const_iterator it = rune_cache_.find(key);
if (it != rune_cache_.end())
return it->second;
if (!rune_cache_.empty()) {
std::unordered_map<uint64_t, int>::const_iterator it =
rune_cache_.find(key);
if (it != rune_cache_.end())
return it->second;
}
int id = UncachedRuneByteSuffix(lo, hi, foldcase, next);
rune_cache_[key] = id;
return id;
Expand All @@ -497,6 +500,8 @@ bool Compiler::IsCachedRuneByteSuffix(int id) {
int next = inst_[id].out();

uint64_t key = MakeRuneCacheKey(lo, hi, foldcase, next);
if (rune_cache_.empty())
return false;
return rune_cache_.find(key) != rune_cache_.end();
}

Expand Down
13 changes: 8 additions & 5 deletions re2/dfa.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,13 @@
#include <deque>
#include <memory>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <utility>
#include <vector>

#include "absl/base/call_once.h"
#include "absl/base/thread_annotations.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/hash/hash.h"
#include "absl/log/absl_check.h"
#include "absl/log/absl_log.h"
Expand Down Expand Up @@ -165,7 +165,7 @@ class DFA {
}
};

typedef absl::flat_hash_set<State*, StateHash, StateEqual> StateSet;
typedef std::unordered_set<State*, StateHash, StateEqual> StateSet;

private:
// Make it easier to swap in a scalable reader-writer mutex.
Expand Down Expand Up @@ -801,6 +801,9 @@ DFA::State* DFA::CachedState(int* inst, int ninst, uint32_t flag) {

// Clear the cache. Must hold cache_mutex_.w or be in destructor.
void DFA::ClearCache() {
if (state_cache_.empty())
return;

StateSet::iterator begin = state_cache_.begin();
StateSet::iterator end = state_cache_.end();
while (begin != end) {
Expand Down Expand Up @@ -1932,7 +1935,7 @@ int DFA::BuildAllStates(const Prog::DFAStateCallback& cb) {
// Add start state to work queue.
// Note that any State* that we handle here must point into the cache,
// so we can simply depend on pointer-as-a-number hashing and equality.
absl::flat_hash_map<State*, int> m;
std::unordered_map<State*, int> m;
std::deque<State*> q;
m.emplace(params.start, static_cast<int>(m.size()));
q.push_back(params.start);
Expand Down Expand Up @@ -2006,7 +2009,7 @@ bool DFA::PossibleMatchRange(std::string* min, std::string* max, int maxlen) {
// Also note that previously_visited_states[UnseenStatePtr] will, in the STL
// tradition, implicitly insert a '0' value at first use. We take advantage
// of that property below.
absl::flat_hash_map<State*, int> previously_visited_states;
std::unordered_map<State*, int> previously_visited_states;

// Pick out start state for anchored search at beginning of text.
RWLocker l(&cache_mutex_);
Expand Down
19 changes: 19 additions & 0 deletions re2/testing/re2_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1196,6 +1196,25 @@ TEST(RE2, NoCrash) {
ASSERT_FALSE(RE2::PartialMatch("a\\b", re));
}

// Issue 596: compiling a UTF-8 char class with a trailing hyphen should not
// crash while consulting the compiler's rune suffix cache.
{
const std::string pattern = "((([\xC3\xA4-])))";
RE2 re(pattern, RE2::Quiet);
ASSERT_TRUE(re.ok());
}

// Issue 589: a tiny DFA memory budget should fail safely without crashing
// while tearing down an empty state cache.
{
RE2::Options opt;
opt.set_log_errors(false);
opt.set_max_mem(4096);
RE2 re("A", opt);
ASSERT_TRUE(re.ok());
ASSERT_TRUE(RE2::PartialMatch("fooAbar", re));
}

// Test that using an enormous regexp doesn't crash
{
RE2 re("(((.{100}){100}){100}){100}", RE2::Quiet);
Expand Down