1/*
2 * Copyright (c) 2024 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 CONTAINERSTREEMAPCOMMON_FUZZER_H
17#define CONTAINERSTREEMAPCOMMON_FUZZER_H
18
19#include "ecmascript/containers/containers_hashmap.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_handle.h"
25#include "ecmascript/napi/include/jsnapi.h"
26
27namespace panda::ecmascript {
28using namespace panda::ecmascript::containers;
29class ContainersHashMapFuzzTestHelper {
30public:
31    static JSFunction *JSObjectCreate(JSThread *thread)
32    {
33        EcmaVM *ecmaVM = thread->GetEcmaVM();
34        JSHandle<GlobalEnv> globalEnv = ecmaVM->GetGlobalEnv();
35        return globalEnv->GetObjectFunction().GetObject<JSFunction>();
36    }
37
38    static EcmaRuntimeCallInfo *CreateEcmaRuntimeCallInfo(JSThread *thread, uint32_t numArgs)
39    {
40        auto factory = thread->GetEcmaVM()->GetFactory();
41        JSHandle<JSTaggedValue> hclass(thread, JSObjectCreate(thread));
42        JSHandle<JSTaggedValue> callee(
43            factory->NewJSObjectByConstructor(JSHandle<JSFunction>::Cast(hclass), hclass));
44        JSHandle<JSTaggedValue> undefined = thread->GlobalConstants()->GetHandledUndefined();
45        EcmaRuntimeCallInfo *objCallInfo =
46            EcmaInterpreter::NewRuntimeCallInfo(thread, undefined, callee, undefined, numArgs);
47        return objCallInfo;
48    }
49
50    static JSTaggedValue InitializeHashMapConstructor(JSThread *thread)
51    {
52        ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
53        JSHandle<GlobalEnv> env = thread->GetEcmaVM()->GetGlobalEnv();
54
55        JSHandle<JSTaggedValue> globalObject = env->GetJSGlobalObject();
56        JSHandle<JSTaggedValue> key(factory->NewFromASCII("ArkPrivate"));
57        JSHandle<JSTaggedValue> value =
58            JSObject::GetProperty(thread, JSHandle<JSTaggedValue>(globalObject), key).GetValue();
59
60        auto objCallInfo = CreateEcmaRuntimeCallInfo(thread, 6);
61        objCallInfo->SetFunction(JSTaggedValue::Undefined());
62        objCallInfo->SetThis(value.GetTaggedValue());
63        objCallInfo->SetCallArg(0, JSTaggedValue(static_cast<int>(ContainerTag::HashMap)));
64        JSTaggedValue result = ContainersPrivate::Load(objCallInfo);
65        return result;
66    }
67
68    static JSHandle<JSAPIHashMap> CreateJSAPIHashMap(JSThread *thread)
69    {
70        JSHandle<JSFunction> newTarget(thread, InitializeHashMapConstructor(thread));
71        auto objCallInfo = CreateEcmaRuntimeCallInfo(thread, 4);
72        objCallInfo->SetFunction(newTarget.GetTaggedValue());
73        objCallInfo->SetNewTarget(newTarget.GetTaggedValue());
74        objCallInfo->SetThis(JSTaggedValue::Undefined());
75
76        JSTaggedValue result = ContainersHashMap::HashMapConstructor(objCallInfo);
77        JSHandle<JSAPIHashMap> map(thread, result);
78        return map;
79    }
80
81    static bool InitializeFuzzTest(const uint8_t *data, size_t size, double &input, EcmaVM *&vm,
82                                   JSThread *&thread)
83    {
84        RuntimeOption option;
85        option.SetLogLevel(RuntimeOption::LOG_LEVEL::ERROR);
86        vm = JSNApi::CreateJSVM(option);
87        thread = vm->GetAssociatedJSThread();
88        if (vm == nullptr || thread == nullptr) {
89            return false;
90        }
91        if (size == 0) {
92            JSNApi::DestroyJSVM(vm);
93            return false;
94        }
95
96        size_t maxByteLen = sizeof(uint32_t);
97        if (size > maxByteLen) {
98            size = maxByteLen;
99        }
100        if (memcpy_s(&input, maxByteLen, data, size) != 0) {
101            std::cout << "memcpy_s failed!";
102            UNREACHABLE();
103        }
104        return true;
105    }
106
107    static void ContainersHashMapEntriesFuzzTest(const uint8_t *data, size_t size)
108    {
109        EcmaVM *vm = nullptr;
110        JSThread *thread = nullptr;
111        double input = 0;
112        if (!InitializeFuzzTest(data, size, input, vm, thread)) {
113            return;
114        }
115
116        JSHandle<JSAPIHashMap> tMap = CreateJSAPIHashMap(thread);
117        auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
118        callInfo->SetFunction(JSTaggedValue::Undefined());
119        callInfo->SetThis(tMap.GetTaggedValue());
120        callInfo->SetCallArg(0, JSTaggedValue(input));
121        callInfo->SetCallArg(1, JSTaggedValue(input));
122        ContainersHashMap::Set(callInfo);
123
124        auto callInfo2 = CreateEcmaRuntimeCallInfo(thread, 4);
125        callInfo2->SetFunction(JSTaggedValue::Undefined());
126        callInfo2->SetThis(tMap.GetTaggedValue());
127        ContainersHashMap::Entries(callInfo2);
128        JSNApi::DestroyJSVM(vm);
129    }
130
131    static void ContainersHashMapFuzzTest(const uint8_t *data, size_t size)
132    {
133        EcmaVM *vm = nullptr;
134        JSThread *thread = nullptr;
135        double input = 0;
136        if (!InitializeFuzzTest(data, size, input, vm, thread)) {
137            return;
138        }
139        JSHandle<JSAPIHashMap> stack = CreateJSAPIHashMap(thread);
140        EcmaRuntimeCallInfo *callInfo = CreateEcmaRuntimeCallInfo(thread, 6);
141        callInfo->SetFunction(JSTaggedValue::Undefined());
142        callInfo->SetThis(stack.GetTaggedValue());
143        callInfo->SetCallArg(0, JSTaggedValue(input));
144        ContainersHashMap::HashMapConstructor(callInfo);
145        JSNApi::DestroyJSVM(vm);
146    }
147
148    static void ContainersHashMapClearFuzzTest(const uint8_t *data, size_t size)
149    {
150        EcmaVM *vm = nullptr;
151        JSThread *thread = nullptr;
152        double input = 0;
153        if (!InitializeFuzzTest(data, size, input, vm, thread)) {
154            return;
155        }
156
157        JSHandle<JSAPIHashMap> tMap = CreateJSAPIHashMap(thread);
158        auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
159        callInfo->SetFunction(JSTaggedValue::Undefined());
160        callInfo->SetThis(tMap.GetTaggedValue());
161        callInfo->SetCallArg(0, JSTaggedValue(input));
162        callInfo->SetCallArg(1, JSTaggedValue(input));
163        ContainersHashMap::Set(callInfo);
164        auto callInfo1 = CreateEcmaRuntimeCallInfo(thread, 4);
165        callInfo1->SetFunction(JSTaggedValue::Undefined());
166        callInfo1->SetThis(tMap.GetTaggedValue());
167        ContainersHashMap::Clear(callInfo1);
168        JSNApi::DestroyJSVM(vm);
169    }
170
171    static void ContainersHashMapForEachFuzzTest(const uint8_t *data, size_t size)
172    {
173        EcmaVM *vm = nullptr;
174        JSThread *thread = nullptr;
175        double input = 0;
176        if (!InitializeFuzzTest(data, size, input, vm, thread)) {
177            return;
178        }
179
180        JSHandle<JSAPIHashMap> tMap = CreateJSAPIHashMap(thread);
181        auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
182        callInfo->SetFunction(JSTaggedValue::Undefined());
183        callInfo->SetThis(tMap.GetTaggedValue());
184        callInfo->SetCallArg(0, JSTaggedValue(input));
185        callInfo->SetCallArg(1, JSTaggedValue(input));
186        ContainersHashMap::Set(callInfo);
187        JSHandle<JSAPIHashMap> dMap = CreateJSAPIHashMap(thread);
188        auto callInfo1 = CreateEcmaRuntimeCallInfo(thread, 8);
189        callInfo1->SetFunction(JSTaggedValue::Undefined());
190        callInfo1->SetThis(tMap.GetTaggedValue());
191        callInfo1->SetCallArg(0, JSTaggedValue::Undefined());
192        callInfo1->SetCallArg(1, dMap.GetTaggedValue());
193        ContainersHashMap::ForEach(callInfo1);
194        JSNApi::DestroyJSVM(vm);
195    }
196
197    static void ContainersHashMapGetFuzzTest(const uint8_t *data, size_t size)
198    {
199        EcmaVM *vm = nullptr;
200        JSThread *thread = nullptr;
201        double input = 0;
202        if (!InitializeFuzzTest(data, size, input, vm, thread)) {
203            return;
204        }
205
206        JSHandle<JSAPIHashMap> tMap = CreateJSAPIHashMap(thread);
207        auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
208        callInfo->SetFunction(JSTaggedValue::Undefined());
209        callInfo->SetThis(tMap.GetTaggedValue());
210        callInfo->SetCallArg(0, JSTaggedValue(input));
211        callInfo->SetCallArg(1, JSTaggedValue(input + 1));
212        ContainersHashMap::Set(callInfo);
213
214        auto callInfo1 = CreateEcmaRuntimeCallInfo(thread, 6);
215        callInfo1->SetFunction(JSTaggedValue::Undefined());
216        callInfo1->SetThis(tMap.GetTaggedValue());
217        callInfo1->SetCallArg(0, JSTaggedValue(input));
218        ContainersHashMap::Get(callInfo1);
219        JSNApi::DestroyJSVM(vm);
220    }
221
222    static void ContainersHashMapGetLengthFuzzTest(const uint8_t *data, size_t size)
223    {
224        EcmaVM *vm = nullptr;
225        JSThread *thread = nullptr;
226        double input = 0;
227        if (!InitializeFuzzTest(data, size, input, vm, thread)) {
228            return;
229        }
230
231        JSHandle<JSAPIHashMap> tMap = CreateJSAPIHashMap(thread);
232        auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
233        callInfo->SetFunction(JSTaggedValue::Undefined());
234        callInfo->SetThis(tMap.GetTaggedValue());
235        callInfo->SetCallArg(0, JSTaggedValue(input));
236        callInfo->SetCallArg(1, JSTaggedValue(input));
237        ContainersHashMap::Set(callInfo);
238
239        auto callInfo1 = CreateEcmaRuntimeCallInfo(thread, 4);
240        callInfo1->SetFunction(JSTaggedValue::Undefined());
241        callInfo1->SetThis(tMap.GetTaggedValue());
242        ContainersHashMap::GetLength(callInfo1);
243        JSNApi::DestroyJSVM(vm);
244    }
245
246    static void ContainersHashMapHasKeyFuzzTest(const uint8_t *data, size_t size)
247    {
248        EcmaVM *vm = nullptr;
249        JSThread *thread = nullptr;
250        double input = 0;
251        if (!InitializeFuzzTest(data, size, input, vm, thread)) {
252            return;
253        }
254
255        JSHandle<JSAPIHashMap> tMap = CreateJSAPIHashMap(thread);
256        auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
257        callInfo->SetFunction(JSTaggedValue::Undefined());
258        callInfo->SetThis(tMap.GetTaggedValue());
259        callInfo->SetCallArg(0, JSTaggedValue(input));
260        callInfo->SetCallArg(1, JSTaggedValue(input));
261        ContainersHashMap::Set(callInfo);
262
263        EcmaRuntimeCallInfo *callInfo1 = CreateEcmaRuntimeCallInfo(thread, 6);
264        callInfo1->SetFunction(JSTaggedValue::Undefined());
265        callInfo1->SetThis(tMap.GetTaggedValue());
266        callInfo1->SetCallArg(0, JSTaggedValue(input));
267        ContainersHashMap::HasKey(callInfo1);
268        JSNApi::DestroyJSVM(vm);
269    }
270
271    static void ContainersHashMapHasValueFuzzTest(const uint8_t *data, size_t size)
272    {
273        EcmaVM *vm = nullptr;
274        JSThread *thread = nullptr;
275        double input = 0;
276        if (!InitializeFuzzTest(data, size, input, vm, thread)) {
277            return;
278        }
279
280        JSHandle<JSAPIHashMap> tMap = CreateJSAPIHashMap(thread);
281        auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
282        callInfo->SetFunction(JSTaggedValue::Undefined());
283        callInfo->SetThis(tMap.GetTaggedValue());
284        callInfo->SetCallArg(0, JSTaggedValue(input));
285        callInfo->SetCallArg(1, JSTaggedValue(input));
286        ContainersHashMap::Set(callInfo);
287
288        EcmaRuntimeCallInfo *callInfo1 = CreateEcmaRuntimeCallInfo(thread, 6);
289        callInfo1->SetFunction(JSTaggedValue::Undefined());
290        callInfo1->SetThis(tMap.GetTaggedValue());
291        callInfo1->SetCallArg(0, JSTaggedValue(input));
292        ContainersHashMap::HasValue(callInfo1);
293        JSNApi::DestroyJSVM(vm);
294    }
295
296    static void ContainersHashMapIsEmptyFuzzTest(const uint8_t *data, size_t size)
297    {
298        EcmaVM *vm = nullptr;
299        JSThread *thread = nullptr;
300        double input = 0;
301        if (!InitializeFuzzTest(data, size, input, vm, thread)) {
302            return;
303        }
304
305        JSHandle<JSAPIHashMap> tMap = CreateJSAPIHashMap(thread);
306        auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
307        callInfo->SetFunction(JSTaggedValue::Undefined());
308        callInfo->SetThis(tMap.GetTaggedValue());
309        callInfo->SetCallArg(0, JSTaggedValue(input));
310        callInfo->SetCallArg(1, JSTaggedValue(input));
311        ContainersHashMap::Set(callInfo);
312        EcmaRuntimeCallInfo *callInfo2 = CreateEcmaRuntimeCallInfo(thread, 4);
313        callInfo2->SetFunction(JSTaggedValue::Undefined());
314        callInfo2->SetThis(tMap.GetTaggedValue());
315        ContainersHashMap::IsEmpty(callInfo2);
316        JSNApi::DestroyJSVM(vm);
317    }
318
319    static void ContainersHashMapKeysFuzzTest(const uint8_t *data, size_t size)
320    {
321        EcmaVM *vm = nullptr;
322        JSThread *thread = nullptr;
323        double input = 0;
324        if (!InitializeFuzzTest(data, size, input, vm, thread)) {
325            return;
326        }
327
328        JSHandle<JSAPIHashMap> tMap = CreateJSAPIHashMap(thread);
329        auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
330        callInfo->SetFunction(JSTaggedValue::Undefined());
331        callInfo->SetThis(tMap.GetTaggedValue());
332        callInfo->SetCallArg(0, JSTaggedValue(input));
333        callInfo->SetCallArg(1, JSTaggedValue(input));
334        ContainersHashMap::Set(callInfo);
335
336        auto callInfo1 = CreateEcmaRuntimeCallInfo(thread, 4);
337        callInfo1->SetFunction(JSTaggedValue::Undefined());
338        callInfo1->SetThis(tMap.GetTaggedValue());
339        ContainersHashMap::Keys(callInfo1);
340        JSNApi::DestroyJSVM(vm);
341    }
342
343    static void ContainersHashMapRemoveFuzzTest(const uint8_t *data, size_t size)
344    {
345        EcmaVM *vm = nullptr;
346        JSThread *thread = nullptr;
347        double input = 0;
348        if (!InitializeFuzzTest(data, size, input, vm, thread)) {
349            return;
350        }
351
352        JSHandle<JSAPIHashMap> tMap = CreateJSAPIHashMap(thread);
353        auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
354        callInfo->SetFunction(JSTaggedValue::Undefined());
355        callInfo->SetThis(tMap.GetTaggedValue());
356        callInfo->SetCallArg(0, JSTaggedValue(input));
357        callInfo->SetCallArg(1, JSTaggedValue(input));
358        ContainersHashMap::Set(callInfo);
359
360        auto callInfo1 = CreateEcmaRuntimeCallInfo(thread, 6);
361        callInfo1->SetFunction(JSTaggedValue::Undefined());
362        callInfo1->SetThis(tMap.GetTaggedValue());
363        callInfo1->SetCallArg(0, JSTaggedValue(input + 1));
364        ContainersHashMap::Remove(callInfo1);
365        JSNApi::DestroyJSVM(vm);
366    }
367
368    static void ContainersHashMapReplaceFuzzTest(const uint8_t *data, size_t size)
369    {
370        EcmaVM *vm = nullptr;
371        JSThread *thread = nullptr;
372        double input = 0;
373        if (!InitializeFuzzTest(data, size, input, vm, thread)) {
374            return;
375        }
376
377        JSHandle<JSAPIHashMap> tMap = CreateJSAPIHashMap(thread);
378        auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
379        callInfo->SetFunction(JSTaggedValue::Undefined());
380        callInfo->SetThis(tMap.GetTaggedValue());
381        callInfo->SetCallArg(0, JSTaggedValue(input));
382        callInfo->SetCallArg(1, JSTaggedValue(input));
383        ContainersHashMap::Set(callInfo);
384
385        EcmaRuntimeCallInfo *callInfo1 = CreateEcmaRuntimeCallInfo(thread, 8);
386        callInfo1->SetFunction(JSTaggedValue::Undefined());
387        callInfo1->SetThis(tMap.GetTaggedValue());
388        callInfo1->SetCallArg(0, JSTaggedValue(input + 1));
389        callInfo1->SetCallArg(1, JSTaggedValue(input));
390        ContainersHashMap::Replace(callInfo1);
391        JSNApi::DestroyJSVM(vm);
392    }
393
394    static void ContainersHashMapSetFuzzTest(const uint8_t *data, size_t size)
395    {
396        EcmaVM *vm = nullptr;
397        JSThread *thread = nullptr;
398        double input = 0;
399        if (!InitializeFuzzTest(data, size, input, vm, thread)) {
400            return;
401        }
402
403        JSHandle<JSAPIHashMap> tMap = CreateJSAPIHashMap(thread);
404        auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
405        callInfo->SetFunction(JSTaggedValue::Undefined());
406        callInfo->SetThis(tMap.GetTaggedValue());
407        callInfo->SetCallArg(0, JSTaggedValue(input));
408        callInfo->SetCallArg(1, JSTaggedValue(input + 1));
409        ContainersHashMap::Set(callInfo);
410        JSNApi::DestroyJSVM(vm);
411    }
412
413    static void ContainersHashMapSetAllFuzzTest(const uint8_t *data, size_t size)
414    {
415        EcmaVM *vm = nullptr;
416        JSThread *thread = nullptr;
417        double input = 0;
418        if (!InitializeFuzzTest(data, size, input, vm, thread)) {
419            return;
420        }
421
422        JSHandle<JSAPIHashMap> tMap = CreateJSAPIHashMap(thread);
423        auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
424        callInfo->SetFunction(JSTaggedValue::Undefined());
425        callInfo->SetThis(tMap.GetTaggedValue());
426        callInfo->SetCallArg(0, JSTaggedValue(input));
427        callInfo->SetCallArg(1, JSTaggedValue(input));
428        ContainersHashMap::Set(callInfo);
429
430        JSHandle<JSAPIHashMap> dMap = CreateJSAPIHashMap(thread);
431        auto callInfo1 = CreateEcmaRuntimeCallInfo(thread, 6);
432        callInfo1->SetFunction(JSTaggedValue::Undefined());
433        callInfo1->SetThis(dMap.GetTaggedValue());
434        callInfo1->SetCallArg(0, tMap.GetTaggedValue());
435        ContainersHashMap::SetAll(callInfo1);
436        JSNApi::DestroyJSVM(vm);
437    }
438
439    static void ContainersHashMapValuesFuzzTest(const uint8_t *data, size_t size)
440    {
441        EcmaVM *vm = nullptr;
442        JSThread *thread = nullptr;
443        double input = 0;
444        if (!InitializeFuzzTest(data, size, input, vm, thread)) {
445            return;
446        }
447
448        JSHandle<JSAPIHashMap> tMap = CreateJSAPIHashMap(thread);
449        auto callInfo = CreateEcmaRuntimeCallInfo(thread, 8);
450        callInfo->SetFunction(JSTaggedValue::Undefined());
451        callInfo->SetThis(tMap.GetTaggedValue());
452        callInfo->SetCallArg(0, JSTaggedValue(input));
453        callInfo->SetCallArg(1, JSTaggedValue(input));
454        ContainersHashMap::Set(callInfo);
455
456        auto callInfo1 = CreateEcmaRuntimeCallInfo(thread, 4);
457        callInfo1->SetFunction(JSTaggedValue::Undefined());
458        callInfo1->SetThis(tMap.GetTaggedValue());
459        ContainersHashMap::Values(callInfo1);
460        JSNApi::DestroyJSVM(vm);
461    }
462};
463}  // namespace panda::ecmascript
464#endif