1 /*
2  * Copyright (c) 2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef CONTAINERSDEQUECOMMON_FUZZER_H
17 #define CONTAINERSDEQUECOMMON_FUZZER_H
18 
19 #include "ecmascript/containers/containers_deque.h"
20 #include "ecmascript/containers/containers_private.h"
21 #include "ecmascript/ecma_string-inl.h"
22 #include "ecmascript/ecma_vm.h"
23 #include "ecmascript/global_env.h"
24 #include "ecmascript/js_api/js_api_deque.h"
25 #include "ecmascript/js_api/js_api_deque_iterator.h"
26 #include "ecmascript/js_handle.h"
27 #include "ecmascript/js_tagged_value-inl.h"
28 #include "ecmascript/napi/include/jsnapi.h"
29 #include "ecmascript/ecma_runtime_call_info.h"
30 #include "ecmascript/js_thread.h"
31 #include "ecmascript/object_factory.h"
32 
33 #define MAXBYTELEN sizeof(unsigned int)
34 
35 namespace panda::ecmascript {
36 using namespace panda::ecmascript::containers;
37 class ContainersDequeFuzzTestHelper {
38 public:
JSObjectCreate(JSThread *thread)39     static JSFunction *JSObjectCreate(JSThread *thread)
40     {
41         EcmaVM *ecmaVM = thread->GetEcmaVM();
42         JSHandle<GlobalEnv> globalEnv = ecmaVM->GetGlobalEnv();
43         return globalEnv->GetObjectFunction().GetObject<JSFunction>();
44     }
45 
CreateEcmaRuntimeCallInfo(JSThread *thread, uint32_t numArgs)46     static EcmaRuntimeCallInfo *CreateEcmaRuntimeCallInfo(JSThread *thread, uint32_t numArgs)
47     {
48         auto factory = thread->GetEcmaVM()->GetFactory();
49         JSHandle<JSTaggedValue> hclass(thread, JSObjectCreate(thread));
50         JSHandle<JSTaggedValue> callee(factory->NewJSObjectByConstructor(JSHandle<JSFunction>::Cast(hclass), hclass));
51         JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
52         EcmaRuntimeCallInfo *objCallInfo =
53             EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, callee, undefined, numArgs);
54         return objCallInfo;
55     }
56 
CreateJSAPIDeque(JSThread *thread)57     static JSHandle<JSAPIDeque> CreateJSAPIDeque(JSThread *thread)
58     {
59         auto factory = thread->GetEcmaVM()->GetFactory();
60         JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
61         JSHandle<JSTaggedValue> globalObject = env->GetJSGlobalObject();
62         JSHandle<JSTaggedValue> key(factory->NewFromASCII("ArkPrivate"));
63         JSHandle<JSTaggedValue> value =
64             JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(globalObject), key).GetValue();
65 
66         auto objCallInfo = CreateEcmaRuntimeCallInfo(thread, 6); // 6 : means the argv length
67         objCallInfo->SetFunction(JSTaggedValue::Undefined());
68         objCallInfo->SetThis(value.GetTaggedValue());
69         objCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(ContainerTag::Deque))); // 0 means the argument
70         JSTaggedValue result = ContainersPrivate::Load(objCallInfo);
71 
72         JSHandle<JSFunction> newTarget(thread, result);
73         auto objCallInfo2 = CreateEcmaRuntimeCallInfo(thread, 6); // 6 : means the argv length
74         objCallInfo2->SetFunction(newTarget.GetTaggedValue());
75         objCallInfo2->SetNewTarget(newTarget.GetTaggedValue());
76         objCallInfo2->SetThis(JSTaggedValue::Undefined());
77         objCallInfo2->SetCallArg(0, JSTaggedValue::Undefined());
78 
79         JSTaggedValue list = ContainersDeque::DequeConstructor(objCallInfo2);
80         JSHandle<JSAPIDeque> deque(thread, list);
81         return deque;
82     }
83 
ContainersDequeInsertFrontFuzzTest(const uint8_t* data, size_t size)84     static void ContainersDequeInsertFrontFuzzTest(const uint8_t* data, size_t size)
85     {
86         RuntimeOption option;
87         option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR);
88         EcmaVM *vm = JSNApi::CreateJSVM(option);
89         {
90             JsiFastNativeScope scope(vm);
91             auto thread = vm->GetAssociatedJSThread();
92             JSHandle<JSAPIDeque> deque = CreateJSAPIDeque(thread);
93 
94             auto callInfo = CreateEcmaRuntimeCallInfo(thread, 6);
95             callInfo->SetFunction(JSTaggedValue::Undefined());
96             callInfo->SetThis(deque.GetTaggedValue());
97             ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
98             std::string str(data, data + size);
99             JSTaggedValue value = factory->NewFromStdString(str).GetTaggedValue();
100             callInfo->SetCallArg(0, value);
101             ContainersDeque::InsertFront(callInfo);
102         }
103         JSNApi::DestroyJSVM(vm);
104     }
105 
106     class TestClass : public base::BuiltinsBase {
107         public:
TestForEachFunc(EcmaRuntimeCallInfo *argv)108             static JSTaggedValue TestForEachFunc(EcmaRuntimeCallInfo *argv)
109             {
110                 JSThread *thread = argv->GetThread();
111                 JSHandle<JSTaggedValue> value = GetCallArg(argv, 0);
112                 JSHandle<JSTaggedValue> index = GetCallArg(argv, 1);
113                 JSHandle<JSTaggedValue> deque = GetCallArg(argv, 2); // 2 means the secode arg
114                 if (!deque->IsUndefined()) {
115                     if (index->IsNumber() && value->IsNumber()) {
116                         JSHandle<JSAPIDeque>::Cast(deque)->Set(thread, index->GetInt(),
117                             JSTaggedValue(value->GetInt() * 2));    // 2 means mul by 2
118                     }
119                 }
120                 return JSTaggedValue::True();
121             }
122     };
123 
ContainersDequeForEachFuzzTest(const uint8_t* data, size_t size)124     static void ContainersDequeForEachFuzzTest(const uint8_t* data, size_t size)
125     {
126         uint32_t input = 0;
127         if (size <= 0) {
128             return;
129         }
130         if (size > MAXBYTELEN) {
131             size = MAXBYTELEN;
132         }
133         if (memcpy_s(&input, MAXBYTELEN, data, size) != 0) {
134             std::cout << "memcpy_s failed!";
135             UNREACHABLE();
136         }
137 
138         RuntimeOption option;
139         option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR);
140         EcmaVM *vm = JSNApi::CreateJSVM(option);
141         {
142             JsiFastNativeScope scope(vm);
143             auto thread = vm->GetAssociatedJSThread();
144 
145             constexpr uint32_t NODE_NUMBERS = 8;
146             JSHandle<JSAPIDeque> deque = CreateJSAPIDeque(thread);
147             for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
148                 auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
149                 callInfo->SetFunction(JSTaggedValue::Undefined());
150                 callInfo->SetThis(deque.GetTaggedValue());
151                 callInfo->SetCallArg(0, JSTaggedValue(i + input));
152                 ContainersDeque::InsertFront(callInfo);
153             }
154 
155             JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
156             JSHandle<JSFunction> func = thread->GetEcmaVM()->GetFactory()->NewJSFunction(env,
157                 reinterpret_cast<void *>(TestClass::TestForEachFunc));
158             auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
159             callInfo->SetFunction(JSTaggedValue::Undefined());
160             callInfo->SetThis(deque.GetTaggedValue());
161             callInfo->SetCallArg(0, func.GetTaggedValue());
162             callInfo->SetCallArg(1, deque.GetTaggedValue());
163             ContainersDeque::ForEach(callInfo);
164         }
165         JSNApi::DestroyJSVM(vm);
166     }
167 
ContainersDequeGetFirstFuzzTest(const uint8_t* data, size_t size)168     static void ContainersDequeGetFirstFuzzTest(const uint8_t* data, size_t size)
169     {
170         RuntimeOption option;
171         option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR);
172         EcmaVM *vm = JSNApi::CreateJSVM(option);
173         {
174             JsiFastNativeScope scope(vm);
175             auto thread = vm->GetAssociatedJSThread();
176 
177             JSHandle<JSAPIDeque> deque = CreateJSAPIDeque(thread);
178             auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
179             callInfo->SetFunction(JSTaggedValue::Undefined());
180             callInfo->SetThis(deque.GetTaggedValue());
181 
182             unsigned int input = 0;
183             if (size <= 0) {
184                 return;
185             }
186             if (size > MAXBYTELEN) {
187                 size = MAXBYTELEN;
188             }
189             if (memcpy_s(&input, MAXBYTELEN, data, size) != 0) {
190                 std::cout << "memcpy_s failed!";
191                 UNREACHABLE();
192             }
193             callInfo->SetCallArg(0, JSTaggedValue(input));
194             ContainersDeque::InsertFront(callInfo);
195             auto callInfo1 = CreateEcmaRuntimeCallInfo(thread, 4);
196             callInfo1->SetFunction(JSTaggedValue::Undefined());
197             callInfo1->SetThis(deque.GetTaggedValue());
198             ContainersDeque::GetFirst(callInfo1);
199         }
200         JSNApi::DestroyJSVM(vm);
201         return;
202     }
203 
ContainersDequeGetLastFuzzTest(const uint8_t* data, size_t size)204     static void ContainersDequeGetLastFuzzTest(const uint8_t* data, size_t size)
205     {
206         RuntimeOption option;
207         option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR);
208         EcmaVM *vm = JSNApi::CreateJSVM(option);
209         {
210             JsiFastNativeScope scope(vm);
211             auto thread = vm->GetAssociatedJSThread();
212 
213             JSHandle<JSAPIDeque> deque = CreateJSAPIDeque(thread);
214             auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
215             callInfo->SetFunction(JSTaggedValue::Undefined());
216             callInfo->SetThis(deque.GetTaggedValue());
217 
218             unsigned int input = 0;
219             if (size <= 0) {
220                 return;
221             }
222             if (size > MAXBYTELEN) {
223                 size = MAXBYTELEN;
224             }
225             if (memcpy_s(&input, MAXBYTELEN, data, size) != 0) {
226                 std::cout << "memcpy_s failed!";
227                 UNREACHABLE();
228             }
229             callInfo->SetCallArg(0, JSTaggedValue(input));
230 
231             ContainersDeque::InsertFront(callInfo);
232 
233             auto callInfo1 = CreateEcmaRuntimeCallInfo(thread, 4);
234             callInfo1->SetFunction(JSTaggedValue::Undefined());
235             callInfo1->SetThis(deque.GetTaggedValue());
236             ContainersDeque::GetLast(callInfo1);
237         }
238         JSNApi::DestroyJSVM(vm);
239         return;
240     }
241 
ContainersDequeInsertEndFuzzTest(const uint8_t* data, size_t size)242     static void ContainersDequeInsertEndFuzzTest(const uint8_t* data, size_t size)
243     {
244         RuntimeOption option;
245         option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR);
246         EcmaVM *vm = JSNApi::CreateJSVM(option);
247         {
248             JsiFastNativeScope scope(vm);
249             auto thread = vm->GetAssociatedJSThread();
250 
251             JSHandle<JSAPIDeque> deque = CreateJSAPIDeque(thread);
252             auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
253             callInfo->SetFunction(JSTaggedValue::Undefined());
254             callInfo->SetThis(deque.GetTaggedValue());
255 
256             unsigned int input = 0;
257             if (size <= 0) {
258                 return;
259             }
260             if (size > MAXBYTELEN) {
261                 size = MAXBYTELEN;
262             }
263             if (memcpy_s(&input, MAXBYTELEN, data, size) != 0) {
264                 std::cout << "memcpy_s failed!";
265                 UNREACHABLE();
266             }
267             callInfo->SetCallArg(0, JSTaggedValue(input));
268             ContainersDeque::InsertEnd(callInfo);
269         }
270         JSNApi::DestroyJSVM(vm);
271         return;
272     }
273 
ContainersDequeHasFuzzTest(const uint8_t* data, size_t size)274     static void ContainersDequeHasFuzzTest(const uint8_t* data, size_t size)
275     {
276         RuntimeOption option;
277         option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR);
278         EcmaVM *vm = JSNApi::CreateJSVM(option);
279         {
280             JsiFastNativeScope scope(vm);
281             auto thread = vm->GetAssociatedJSThread();
282 
283             JSHandle<JSAPIDeque> deque = CreateJSAPIDeque(thread);
284             auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
285             callInfo->SetFunction(JSTaggedValue::Undefined());
286             callInfo->SetThis(deque.GetTaggedValue());
287 
288             unsigned int input = 0;
289             if (size <= 0) {
290                 return;
291             }
292             if (size > MAXBYTELEN) {
293                 size = MAXBYTELEN;
294             }
295             if (memcpy_s(&input, MAXBYTELEN, data, size) != 0) {
296                 std::cout << "memcpy_s failed!";
297                 UNREACHABLE();
298             }
299             callInfo->SetCallArg(0, JSTaggedValue(input));
300 
301             ContainersDeque::InsertEnd(callInfo);
302 
303             auto callInfo1 = CreateEcmaRuntimeCallInfo(thread, 8);
304             callInfo1->SetFunction(JSTaggedValue::Undefined());
305             callInfo1->SetThis(deque.GetTaggedValue());
306             callInfo1->SetCallArg(0, JSTaggedValue(input));
307             ContainersDeque::Has(callInfo1);
308         }
309         JSNApi::DestroyJSVM(vm);
310         return;
311     }
312 
ContainersDequePopFirstFuzzTest(const uint8_t* data, size_t size)313     static void ContainersDequePopFirstFuzzTest(const uint8_t* data, size_t size)
314     {
315         RuntimeOption option;
316         option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR);
317         EcmaVM *vm = JSNApi::CreateJSVM(option);
318         {
319             JsiFastNativeScope scope(vm);
320             auto thread = vm->GetAssociatedJSThread();
321 
322             JSHandle<JSAPIDeque> deque = CreateJSAPIDeque(thread);
323             auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
324             callInfo->SetFunction(JSTaggedValue::Undefined());
325             callInfo->SetThis(deque.GetTaggedValue());
326 
327             unsigned int input = 0;
328             if (size <= 0) {
329                 return;
330             }
331             if (size > MAXBYTELEN) {
332                 size = MAXBYTELEN;
333             }
334             if (memcpy_s(&input, MAXBYTELEN, data, size) != 0) {
335                 std::cout << "memcpy_s failed!";
336                 UNREACHABLE();
337             }
338             callInfo->SetCallArg(0, JSTaggedValue(input));
339             ContainersDeque::InsertFront(callInfo);
340             auto callInfo1 = CreateEcmaRuntimeCallInfo(thread, 4);
341             callInfo1->SetFunction(JSTaggedValue::Undefined());
342             callInfo1->SetThis(deque.GetTaggedValue());
343             ContainersDeque::PopFirst(callInfo1);
344         }
345         JSNApi::DestroyJSVM(vm);
346         return;
347     }
348 
ContainersDequePopLastFuzzTest(const uint8_t* data, size_t size)349     static void ContainersDequePopLastFuzzTest(const uint8_t* data, size_t size)
350     {
351         RuntimeOption option;
352         option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR);
353         EcmaVM *vm = JSNApi::CreateJSVM(option);
354         {
355             JsiFastNativeScope scope(vm);
356             auto thread = vm->GetAssociatedJSThread();
357 
358             JSHandle<JSAPIDeque> deque = CreateJSAPIDeque(thread);
359             auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
360             callInfo->SetFunction(JSTaggedValue::Undefined());
361             callInfo->SetThis(deque.GetTaggedValue());
362 
363             unsigned int input = 0;
364             if (size <= 0) {
365                 return;
366             }
367             if (size > MAXBYTELEN) {
368                 size = MAXBYTELEN;
369             }
370             if (memcpy_s(&input, MAXBYTELEN, data, size) != 0) {
371                 std::cout << "memcpy_s failed!";
372                 UNREACHABLE();
373             }
374             callInfo->SetCallArg(0, JSTaggedValue(input));
375             ContainersDeque::InsertFront(callInfo);
376             auto callInfo1 = CreateEcmaRuntimeCallInfo(thread, 4);
377             callInfo1->SetFunction(JSTaggedValue::Undefined());
378             callInfo1->SetThis(deque.GetTaggedValue());
379             ContainersDeque::PopLast(callInfo1);
380         }
381         JSNApi::DestroyJSVM(vm);
382         return;
383     }
384 
ContainersDequeIteratorFuzzTest(const uint8_t* data, size_t size)385     static void ContainersDequeIteratorFuzzTest(const uint8_t* data, size_t size)
386     {
387         RuntimeOption option;
388         option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR);
389         EcmaVM *vm = JSNApi::CreateJSVM(option);
390         {
391             JsiFastNativeScope scope(vm);
392             auto thread = vm->GetAssociatedJSThread();
393 
394             uint32_t input = 0;
395             if (size <= 0) {
396                 return;
397             }
398             if (size > MAXBYTELEN) {
399                 size = MAXBYTELEN;
400             }
401             if (memcpy_s(&input, MAXBYTELEN, data, size) != 0) {
402                 std::cout << "memcpy_s failed!";
403                 UNREACHABLE();
404             }
405 
406             constexpr uint32_t NODE_NUMBERS = 8;
407             JSHandle<JSAPIDeque> deque = CreateJSAPIDeque(thread);
408             for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
409                 auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
410                 callInfo->SetFunction(JSTaggedValue::Undefined());
411                 callInfo->SetThis(deque.GetTaggedValue());
412                 callInfo->SetCallArg(0, JSTaggedValue(i + input));
413 
414                 ContainersDeque::InsertEnd(callInfo);
415             }
416 
417             auto callInfo1 = CreateEcmaRuntimeCallInfo(thread, 4);
418             callInfo1->SetFunction(JSTaggedValue::Undefined());
419             callInfo1->SetThis(deque.GetTaggedValue());
420             JSHandle<JSTaggedValue> iterValues(thread, ContainersDeque::GetIteratorObj(callInfo1));
421 
422             JSMutableHandle<JSTaggedValue> result(thread, JSTaggedValue::Undefined());
423             for (uint32_t i = 0; i < NODE_NUMBERS; i++) {
424                 auto callInfo = CreateEcmaRuntimeCallInfo(thread, 4);
425                 callInfo->SetFunction(JSTaggedValue::Undefined());
426                 callInfo->SetThis(iterValues.GetTaggedValue());
427                 result.Update(JSAPIDequeIterator::Next(callInfo));
428             }
429         }
430         JSNApi::DestroyJSVM(vm);
431         return;
432     }
433 };
434 }
435 #endif