Bug 1874684 - Part 21: Rename SecondsAndNanoseconds::toTotalNanoseconds. r=dminor
[gecko.git] / js / src / fuzz-tests / testRegExp.cpp
blob95ebc8f1bd30f412a97f75ee5e257fa3a14468fe
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:
3 */
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"
10 #include "jsapi.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"
20 using namespace JS;
21 using namespace js;
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);
32 });
34 const uint32_t HEADER_LEN = 2;
35 if (size <= HEADER_LEN) {
36 return 0;
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);
57 } else {
58 inputChars = patternChars + patternLength;
61 Rooted<JSAtom*> pattern(gCx,
62 AtomizeUTF8Chars(gCx, patternChars, patternLength));
63 if (!pattern) {
64 ReportOutOfMemory(gCx);
65 return 0;
67 Rooted<JSAtom*> input(gCx, AtomizeUTF8Chars(gCx, inputChars, inputLength));
68 if (!input) {
69 ReportOutOfMemory(gCx);
70 return 0;
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()) {
81 return 0;
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()) {
90 return 0;
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++) {
101 MOZ_RELEASE_ASSERT(
102 interpretedMatches[i].start == compiledMatches[i].start &&
103 interpretedMatches[i].limit == compiledMatches[i].limit);
106 return 0;
109 MOZ_FUZZING_INTERFACE_RAW(testRegExpInit, /* init function */
110 testRegExpFuzz, /* fuzzing function */
111 RegExp /* module name */