re2 1.25.1 → 1.25.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -436,7 +436,8 @@ Tables are baked in at build time from Unicode 17.0. To target a newer Unicode v
436
436
 
437
437
  ## Release history
438
438
 
439
- - 1.25.1 *Security fix (GHSA-8hcv-x26h-mcgp): a global `replace()` using an output-amplifying template (`$'` or `` $` ``) on very large input could exceed V8's maximum string length and abort the whole process. It now throws a catchable `RangeError`, matching the built-in engine.*
439
+ - 1.25.2 *Two DoS security fixes: a global `match()` with an empty-matchable pattern (`a*`, `(?:)`, …) no longer loops forever exhausting memory (GHSA-6hxr-mr5r-9836), and an out-of-range `lastIndex` on a non-ASCII subject no longer reads past the buffer and crashes (GHSA-ff84-5f28-78qj). Both now match the built-in engine. Thx, [ataberk-xyz](https://github.com/ataberk-xyz).*
440
+ - 1.25.1 *Security fix (GHSA-8hcv-x26h-mcgp): a global `replace()` using an output-amplifying template (`$'` or `` $` ``) on very large input could exceed V8's maximum string length and abort the whole process. It now throws a catchable `RangeError`, matching the built-in engine. Thx, [ataberk-xyz](https://github.com/ataberk-xyz).*
440
441
  - 1.25.0 *Full Unicode 17.0.0 property classes (Fixes #226). New `maxMem` option for `RE2.Set`. Faster matching on pure-ASCII inputs. Narrowed Node support — drops Node 25.x and older patch releases.*
441
442
  - 1.24.1 *Support for Node 22, 24, 26 + precompiled binaries.*
442
443
  - 1.24.0 *Fixed multi-threaded crash in worker threads (#235). Added named import: `import {RE2} from 're2'`. Added CJS test. Updated docs and dependencies.*
package/lib/addon.cc CHANGED
@@ -197,10 +197,13 @@ const StrVal &WrappedRE2::prepareArgument(const v8::Local<v8::Value> &arg, bool
197
197
  auto isolate = v8::Isolate::GetCurrent();
198
198
 
199
199
  auto s = t.ToLocalChecked();
200
- auto argLength = utf8Length(s, isolate);
201
- // Pure ASCII iff the UTF-16 length (s->Length(), O(1)) equals the UTF-8
202
- // byte length: any non-ASCII char makes the byte count strictly larger.
203
- bool isAscii = static_cast<size_t>(s->Length()) == argLength;
200
+ // length validation walks UTF-16 code units, so lastIndex must be bounded by
201
+ // the UTF-16 length (s->Length(), O(1)) not the UTF-8 byte length, which is
202
+ // larger for non-ASCII and would let an out-of-range lastIndex read past the buffer.
203
+ auto argLength = static_cast<size_t>(s->Length());
204
+ // Pure ASCII iff the UTF-16 length equals the UTF-8 byte length: any
205
+ // non-ASCII char makes the byte count strictly larger.
206
+ bool isAscii = argLength == utf8Length(s, isolate);
204
207
 
205
208
  auto buffer = node::Buffer::New(isolate, s).ToLocalChecked();
206
209
  lastCache.Reset(buffer);
@@ -260,7 +263,7 @@ void StrVal::setIndex(size_t newIndex)
260
263
  return;
261
264
  }
262
265
 
263
- byteIndex = index < newIndex ? getUtf16PositionByCounter(data, byteIndex, newIndex - index) : getUtf16PositionByCounter(data, 0, newIndex);
266
+ byteIndex = index < newIndex ? getUtf16PositionByCounter(data, size, byteIndex, newIndex - index) : getUtf16PositionByCounter(data, size, 0, newIndex);
264
267
  index = newIndex;
265
268
  }
266
269
 
package/lib/match.cc CHANGED
@@ -45,7 +45,16 @@ NAN_METHOD(WrappedRE2::Match)
45
45
  while (re2->regexp.Match(str, byteIndex, str.size, anchor, &match, 1))
46
46
  {
47
47
  groups.push_back(match);
48
- byteIndex = match.data() - str.data + match.size();
48
+ size_t offset = match.data() - str.data;
49
+ if (match.size())
50
+ {
51
+ byteIndex = offset + match.size();
52
+ }
53
+ else
54
+ {
55
+ // zero-width match: advance one code point or the loop never terminates
56
+ byteIndex = offset + (offset < str.size ? getUtf8CharSize(str.data[offset]) : 1);
57
+ }
49
58
  }
50
59
 
51
60
  if (groups.empty())
package/lib/wrapped_re2.h CHANGED
@@ -261,9 +261,9 @@ inline void writeUtf8(v8::Local<v8::String> s, v8::Isolate *isolate, char *buffe
261
261
 
262
262
  #endif
263
263
 
264
- inline size_t getUtf16PositionByCounter(const char *data, size_t from, size_t n)
264
+ inline size_t getUtf16PositionByCounter(const char *data, size_t size, size_t from, size_t n)
265
265
  {
266
- for (; n > 0; --n)
266
+ for (; n > 0 && from < size; --n)
267
267
  {
268
268
  size_t s = getUtf8CharSize(data[from]);
269
269
  from += s;
@@ -271,5 +271,5 @@ inline size_t getUtf16PositionByCounter(const char *data, size_t from, size_t n)
271
271
  --n; // this utf8 character will take two utf16 characters
272
272
  // the decrement above is protected to avoid an overflow of an unsigned integer
273
273
  }
274
- return from;
274
+ return from > size ? size : from;
275
275
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "re2",
3
- "version": "1.25.1",
3
+ "version": "1.25.2",
4
4
  "description": "Bindings for RE2: fast, safe alternative to backtracking regular expression engines.",
5
5
  "homepage": "https://github.com/uhop/node-re2",
6
6
  "bugs": "https://github.com/uhop/node-re2/issues",