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
35namespace panda::ecmascript {
36using namespace panda::ecmascript::containers;
37class ContainersDequeFuzzTestHelper {
38public:
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
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
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
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:
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
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
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
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
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
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
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
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
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