re2 1.25.0 → 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 +3 -7
- package/lib/addon.cc +8 -5
- package/lib/match.cc +10 -1
- package/lib/replace.cc +29 -4
- package/lib/wrapped_re2.h +3 -3
- package/package.json +3 -5
package/README.md
CHANGED
|
@@ -251,13 +251,7 @@ See the wiki for notes on [yarn](https://github.com/uhop/node-re2/wiki/Using-wit
|
|
|
251
251
|
|
|
252
252
|
### Supported Node.js versions
|
|
253
253
|
|
|
254
|
-
`re2` supports
|
|
255
|
-
|
|
256
|
-
```
|
|
257
|
-
^22.22.2 || ^24.15.0 || >=26.0.0
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
As of 1.25.0 this range was narrowed to mirror [`node-gyp`](https://github.com/nodejs/node-gyp) 13, which `re2` builds with (and which fixes a Node 26 build on Windows): **Node 25.x and the older 22.0–22.22.1 / 24.0–24.14 patch ranges are no longer supported.** Use a current release of an active line — Node 22 (≥ 22.22.2), 24 (≥ 24.15.0), or 26 and later.
|
|
254
|
+
`re2` supports every non-EOL Node.js release — current and active LTS lines. As a native (`nan`) addon it runs on Node.js only, not Bun or Deno. The authoritative supported range is the `engines` field in `package.json`; it also pins the minimum patch releases the build toolchain ([`node-gyp`](https://github.com/nodejs/node-gyp) 13) requires. Check `engines` for the exact floor rather than a version repeated here.
|
|
261
255
|
|
|
262
256
|
### Install scripts (npm 12+)
|
|
263
257
|
|
|
@@ -442,6 +436,8 @@ Tables are baked in at build time from Unicode 17.0. To target a newer Unicode v
|
|
|
442
436
|
|
|
443
437
|
## Release history
|
|
444
438
|
|
|
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).*
|
|
445
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.*
|
|
446
442
|
- 1.24.1 *Support for Node 22, 24, 26 + precompiled binaries.*
|
|
447
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
|
-
|
|
201
|
-
//
|
|
202
|
-
//
|
|
203
|
-
|
|
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
|
-
|
|
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/replace.cc
CHANGED
|
@@ -315,7 +315,13 @@ inline Nan::Maybe<std::string> replace(
|
|
|
315
315
|
const auto data = item.data();
|
|
316
316
|
if (data)
|
|
317
317
|
{
|
|
318
|
-
|
|
318
|
+
auto buffer = Nan::CopyBuffer(data, item.size());
|
|
319
|
+
if (buffer.IsEmpty())
|
|
320
|
+
{
|
|
321
|
+
Nan::ThrowRangeError("Invalid string length");
|
|
322
|
+
return Nan::Nothing<std::string>();
|
|
323
|
+
}
|
|
324
|
+
argv.push_back(buffer.ToLocalChecked());
|
|
319
325
|
}
|
|
320
326
|
else
|
|
321
327
|
{
|
|
@@ -332,7 +338,13 @@ inline Nan::Maybe<std::string> replace(
|
|
|
332
338
|
const auto data = item.data();
|
|
333
339
|
if (data)
|
|
334
340
|
{
|
|
335
|
-
|
|
341
|
+
auto text = Nan::New(data, item.size());
|
|
342
|
+
if (text.IsEmpty())
|
|
343
|
+
{
|
|
344
|
+
Nan::ThrowRangeError("Invalid string length");
|
|
345
|
+
return Nan::Nothing<std::string>();
|
|
346
|
+
}
|
|
347
|
+
argv.push_back(text.ToLocalChecked());
|
|
336
348
|
}
|
|
337
349
|
else
|
|
338
350
|
{
|
|
@@ -551,8 +563,21 @@ NAN_METHOD(WrappedRE2::Replace)
|
|
|
551
563
|
|
|
552
564
|
if (replacee.isBuffer)
|
|
553
565
|
{
|
|
554
|
-
|
|
566
|
+
auto buffer = Nan::CopyBuffer(result.data(), result.size());
|
|
567
|
+
if (buffer.IsEmpty())
|
|
568
|
+
{
|
|
569
|
+
Nan::ThrowRangeError("Invalid string length");
|
|
570
|
+
return;
|
|
571
|
+
}
|
|
572
|
+
info.GetReturnValue().Set(buffer.ToLocalChecked());
|
|
573
|
+
return;
|
|
574
|
+
}
|
|
575
|
+
// over-max-length result -> empty MaybeLocal; ToLocalChecked() would abort()
|
|
576
|
+
auto text = Nan::New(result);
|
|
577
|
+
if (text.IsEmpty())
|
|
578
|
+
{
|
|
579
|
+
Nan::ThrowRangeError("Invalid string length");
|
|
555
580
|
return;
|
|
556
581
|
}
|
|
557
|
-
info.GetReturnValue().Set(
|
|
582
|
+
info.GetReturnValue().Set(text.ToLocalChecked());
|
|
558
583
|
}
|
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.
|
|
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",
|
|
@@ -22,11 +22,11 @@
|
|
|
22
22
|
"node-gyp": "^13.0.0"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
|
-
"@types/node": "^
|
|
25
|
+
"@types/node": "^26.0.1",
|
|
26
26
|
"@unicode/unicode-17.0.0": "^1.6.17",
|
|
27
27
|
"nano-benchmark": "^1.0.16",
|
|
28
28
|
"prettier": "^3.8.4",
|
|
29
|
-
"tape-six": "^1.
|
|
29
|
+
"tape-six": "^1.14.0",
|
|
30
30
|
"tape-six-proc": "^1.3.1",
|
|
31
31
|
"typescript": "^6.0.3"
|
|
32
32
|
},
|
|
@@ -65,8 +65,6 @@
|
|
|
65
65
|
],
|
|
66
66
|
"author": "Eugene Lazutkin <eugene.lazutkin@gmail.com> (https://lazutkin.com/)",
|
|
67
67
|
"funding": "https://github.com/sponsors/uhop",
|
|
68
|
-
"llms": "https://raw.githubusercontent.com/uhop/node-re2/master/llms.txt",
|
|
69
|
-
"llmsFull": "https://raw.githubusercontent.com/uhop/node-re2/master/llms-full.txt",
|
|
70
68
|
"license": "BSD-3-Clause",
|
|
71
69
|
"tape6": {
|
|
72
70
|
"tests": [
|