1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
8 #include "mozilla/ScopeExit.h"
12 #include "fuzz-tests/tests.h"
13 #include "irregexp/RegExpAPI.h"
14 #include "vm/Interpreter.h"
15 #include "vm/JSAtomUtils.h" // AtomizeUTF8Chars
16 #include "vm/MatchPairs.h"
18 #include "vm/JSContext-inl.h"
23 extern JS::PersistentRootedObject gGlobal
;
24 extern JSContext
* gCx
;
26 static int testRegExpInit(int* argc
, char*** argv
) { return 0; }
28 static int testRegExpFuzz(const uint8_t* buf
, size_t size
) {
29 auto gcGuard
= mozilla::MakeScopeExit([&] {
30 JS::PrepareForFullGC(gCx
);
31 JS::NonIncrementalGC(gCx
, JS::GCOptions::Normal
, JS::GCReason::API
);
34 const uint32_t HEADER_LEN
= 2;
35 if (size
<= HEADER_LEN
) {
39 uint8_t rawFlags
= buf
[0];
40 int32_t patternLength
= buf
[1];
42 const uint32_t startIndex
= 0;
44 RegExpFlags
flags(rawFlags
& RegExpFlag::AllFlags
);
46 int32_t inputLength
= size
- HEADER_LEN
- patternLength
;
48 const char* patternChars
= reinterpret_cast<const char*>(buf
+ HEADER_LEN
);
50 const char* inputChars
;
51 if (inputLength
< 0) {
52 patternLength
= size
- HEADER_LEN
;
54 bool useUnicodeInput
= (buf
[1] & 1) == 0;
55 inputChars
= useUnicodeInput
? "Привет мир" : "Hello\nworld!";
56 inputLength
= strlen(inputChars
);
58 inputChars
= patternChars
+ patternLength
;
61 Rooted
<JSAtom
*> pattern(gCx
,
62 AtomizeUTF8Chars(gCx
, patternChars
, patternLength
));
64 ReportOutOfMemory(gCx
);
67 Rooted
<JSAtom
*> input(gCx
, AtomizeUTF8Chars(gCx
, inputChars
, inputLength
));
69 ReportOutOfMemory(gCx
);
73 VectorMatchPairs interpretedMatches
;
74 VectorMatchPairs compiledMatches
;
76 RegExpRunStatus iStatus
= irregexp::ExecuteForFuzzing(
77 gCx
, pattern
, input
, flags
, startIndex
, &interpretedMatches
,
78 RegExpShared::CodeKind::Bytecode
);
79 if (iStatus
== RegExpRunStatus::Error
) {
80 if (gCx
->isThrowingOverRecursed()) {
83 gCx
->clearPendingException();
85 RegExpRunStatus cStatus
= irregexp::ExecuteForFuzzing(
86 gCx
, pattern
, input
, flags
, startIndex
, &compiledMatches
,
87 RegExpShared::CodeKind::Jitcode
);
88 if (cStatus
== RegExpRunStatus::Error
) {
89 if (gCx
->isThrowingOverRecursed()) {
92 gCx
->clearPendingException();
95 // Use release asserts to enable fuzzing on non-debug builds.
96 MOZ_RELEASE_ASSERT(iStatus
== cStatus
);
97 if (iStatus
== RegExpRunStatus::Success
) {
98 MOZ_RELEASE_ASSERT(interpretedMatches
.pairCount() ==
99 compiledMatches
.pairCount());
100 for (uint32_t i
= 0; i
< interpretedMatches
.pairCount(); i
++) {
102 interpretedMatches
[i
].start
== compiledMatches
[i
].start
&&
103 interpretedMatches
[i
].limit
== compiledMatches
[i
].limit
);
109 MOZ_FUZZING_INTERFACE_RAW(testRegExpInit
, /* init function */
110 testRegExpFuzz
, /* fuzzing function */
111 RegExp
/* module name */