1 /*
2 * Copyright (c) Huawei Technologies Co., Ltd. 2024-2025. All rights reserved.
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 #include <cstddef>
17 #include <cstdlib>
18 #include <js_native_api.h>
19 #include <js_native_api_types.h>
20 #include <node_api.h>
21 #include <securec.h>
22 #include <string>
23 #include <sys/wait.h>
24 #include <unistd.h>
25 #include "napi/native_api.h"
26
27 constexpr int MAX_BUFFER_SIZE = 128;
28 constexpr const char *UBSAN_LOG_FILE_PATH = "/data/storage/el2/log/ubsanXtsLog.com.thirdparty.ubsan.napitest";
29
GetBuffer(int pid)30 static std::string GetBuffer(int pid)
31 {
32 std::string buffer;
33 char file[MAX_BUFFER_SIZE];
34 int filePathRes = snprintf_s(file, sizeof(file), sizeof(file) - 1, "%s.%d", UBSAN_LOG_FILE_PATH, pid);
35 if (filePathRes < 0) {
36 return buffer;
37 }
38 FILE *fp = fopen(file, "r+");
39 if (!fp) {
40 return buffer;
41 }
42 if (fseek(fp, 0, SEEK_END) == -1) {
43 return buffer;
44 }
45 int size = ftell(fp);
46 if (size <= 0) {
47 ftruncate(fileno(fp), 0);
48 rewind(fp);
49 fclose(fp);
50 return buffer;
51 }
52 buffer.resize(size);
53 if (fseek(fp, 0, SEEK_SET) == -1) {
54 ftruncate(fileno(fp), 0);
55 rewind(fp);
56 fclose(fp);
57 return buffer;
58 }
59 int rsize = fread(&buffer[0], 1, size, fp);
60 if (rsize == 0) {
61 ftruncate(fileno(fp), 0);
62 rewind(fp);
63 fclose(fp);
64 return buffer;
65 }
66 ftruncate(fileno(fp), 0);
67 rewind(fp);
68 fclose(fp);
69 return buffer;
70 }
71
CheckUBSanLog(const std::string & errType,const std::string & buffer)72 static bool CheckUBSanLog(const std::string& errType, const std::string& buffer)
73 {
74 if (buffer.empty()) {
75 return false;
76 }
77 bool checkEventTypeFail = buffer.find(errType.c_str()) == std::string::npos;
78 if (checkEventTypeFail) {
79 return false;
80 }
81 return true;
82 }
83 // To detect reads from, or writes to, a misaligned pointer,
84 // or when you create a misaligned reference.
85 // A pointer misaligns if its address isn’t a multiple of its type’s alignment.
MisAlign(napi_env env,napi_callback_info info)86 __attribute__((optnone)) static napi_value MisAlign(napi_env env, napi_callback_info info)
87 {
88 // deliberately convert in C-style cast to trigger UBSan check
89 signed short int *buffer = (signed short int *)malloc(64);
90 if (buffer == nullptr) {
91 return nullptr;
92 }
93 signed long int *pointer = reinterpret_cast<signed long int *>(buffer + 1);
94 *pointer = 42; // 42 is an arbitrary number to deliberately trigger UBSan check
95 std::string bufferLog = GetBuffer(getpid());
96 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:94:5", bufferLog) &&
97 CheckUBSanLog("runtime error: store to misaligned address", bufferLog) &&
98 CheckUBSanLog("for type 'long', which requires 8 byte alignment", bufferLog);
99 int checkRes = findUBSanLog ? 1 : 0;
100 napi_value result = nullptr;
101 napi_create_int32(env, checkRes, &result);
102 return result;
103 }
104
105 // To access indexes that exceed the array’s bounds.
Bounds(napi_env env,napi_callback_info info)106 __attribute__((optnone)) static napi_value Bounds(napi_env env, napi_callback_info info)
107 {
108 size_t argc = 1;
109 napi_value args[1] = {nullptr};
110 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
111 int param;
112 napi_get_value_int32(env, args[0], ¶m);
113 int array[5] = {0};
114 int res = array[param];
115 std::string bufferLog = GetBuffer(getpid());
116 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:114:15", bufferLog) &&
117 CheckUBSanLog("runtime error: index 5 out of bounds for type 'int[5]'", bufferLog);
118 int checkRes = findUBSanLog ? 1 : 0;
119 napi_value result = nullptr;
120 napi_create_int32(env, checkRes, &result);
121 return result;
122 }
123
124 // To detect integer and float division where the divisor is zero.
IntegerDivBy0(napi_env env,napi_callback_info info)125 __attribute__((optnone)) static napi_value IntegerDivBy0(napi_env env, napi_callback_info info)
126 {
127 size_t argc = 1;
128 napi_value args[1] = {nullptr};
129 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
130 int param;
131 napi_get_value_int32(env, args[0], ¶m);
132 int res = 2 / param; // deliberately assign divisor to 0 to trigger UBSan check
133 std::string bufferLog = GetBuffer(getpid());
134 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:132:17", bufferLog) &&
135 CheckUBSanLog("runtime error: division by zero", bufferLog);
136 int checkRes = findUBSanLog ? 1 : 0;
137 napi_value result = nullptr;
138 napi_create_int32(env, checkRes, &result);
139 return result;
140 }
141
142 // To detect accesses of an enumeration variable
143 // when its value isn’t within the valid range for the type.
144 // This can occur for uninitialized enumeration values,
145 // or when using an integer as an enumeration value without an appropriate cast.
146 enum E {
147 A = 1,
148 B = 2
149 };
150
EnumSan(napi_env env,napi_callback_info info)151 __attribute__((optnone)) static napi_value EnumSan(napi_env env, napi_callback_info info)
152 {
153 size_t argc = 1;
154 napi_value args[1] = {nullptr};
155 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
156 int param;
157 napi_get_value_int32(env, args[0], ¶m);
158 // deliberately convert from integer to enum to trigger the undefined behavior of enum
159 enum E *e = reinterpret_cast<enum E*>(¶m);
160 if (*e == A) {
161 int res = 1;
162 }
163 std::string bufferLog = GetBuffer(getpid());
164 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:160:9", bufferLog) &&
165 CheckUBSanLog("runtime error: load of value 42, which is not a valid value for type 'enum E'", bufferLog);
166 int checkRes = findUBSanLog ? 1 : 0;
167 napi_value result = nullptr;
168 napi_create_int32(env, checkRes, &result);
169 return result;
170 }
171
172 // To detect out-of-range casts to, from, or between floating-point types.
FloatCastOverflow(napi_env env,napi_callback_info info)173 __attribute__((optnone)) static napi_value FloatCastOverflow(napi_env env, napi_callback_info info)
174 {
175 // deliberately convert from double to integer
176 // to trigger the undefined behavior of float-cast-overflow
177 double n = 10e50;
178 int res = static_cast<int>(n);
179 std::string bufferLog = GetBuffer(getpid());
180 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:178:32", bufferLog) &&
181 CheckUBSanLog("runtime error: 1e+51 is outside the range of representable values of type 'int'", bufferLog);
182 int checkRes = findUBSanLog ? 1 : 0;
183 napi_value result = nullptr;
184 napi_create_int32(env, checkRes, &result);
185 return result;
186 }
187
188 // To detect signed integer overflows in addition, subtraction, multiplication, and division.
SignedIntegerOverflow(napi_env env,napi_callback_info info)189 __attribute__((optnone)) static napi_value SignedIntegerOverflow(napi_env env, napi_callback_info info)
190 {
191 size_t argc = 1;
192 napi_value args[1] = {nullptr};
193 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
194 int param;
195 napi_get_value_int32(env, args[0], ¶m);
196 int res = param * 42; // 42 is an arbitrary number to deliberately trigger UBSan check
197 std::string bufferLog = GetBuffer(getpid());
198 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:196:21", bufferLog) &&
199 CheckUBSanLog("runtime error: signed integer overflow: 1073741824 * 42 cannot be represented in type 'int'",
200 bufferLog);
201 int checkRes = findUBSanLog ? 1 : 0;
202 napi_value result = nullptr;
203 napi_create_int32(env, checkRes, &result);
204 return result;
205 }
206
207 struct Animal {
208 virtual const char* Speak() = 0;
209 };
210
211 struct Cat: public Animal {
SpeakCat212 const char* Speak() override
213 {
214 return "meow";
215 }
216 };
217
218 struct Dog: public Animal {
SpeakDog219 const char* Speak() override
220 {
221 return "woof";
222 }
223 };
224
Vptr(Animal * obj)225 const char* Vptr(Animal* obj)
226 {
227 auto *dog = reinterpret_cast<Dog*>(obj);
228 return dog->Speak();
229 }
230
231 // To detect when an object has the wrong dynamic type.
VptrCheck(napi_env env,napi_callback_info info)232 __attribute__((optnone)) static napi_value VptrCheck(napi_env env, napi_callback_info info)
233 {
234 Vptr(new Cat);
235 std::string bufferLog = GetBuffer(getpid());
236 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:228:17", bufferLog) &&
237 CheckUBSanLog("runtime error: member call on address", bufferLog) &&
238 CheckUBSanLog("which does not point to an object of type 'Dog'", bufferLog);
239 int checkRes = findUBSanLog ? 1 : 0;
240 napi_value result = nullptr;
241 napi_create_int32(env, checkRes, &result);
242 return result;
243 }
244
245 // To detect when a function that has an argument with the nonnull attribute receives a null value.
Foo0(void * p)246 __attribute__((optnone)) int Foo0(__attribute__((nonnull)) void *p)
247 {
248 return 1;
249 }
250
NonnullAttribute(napi_env env,napi_callback_info info)251 __attribute__((optnone)) static napi_value NonnullAttribute(napi_env env, napi_callback_info info)
252 {
253 size_t argc = 1;
254 napi_value args[1] = {nullptr};
255 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
256 void* arr[3] = {nullptr, malloc(4), nullptr};
257 int param;
258 napi_get_value_int32(env, args[0], ¶m);
259 int res = Foo0(arr[param]);
260 std::string bufferLog = GetBuffer(getpid());
261 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:259:20", bufferLog) &&
262 CheckUBSanLog("runtime error: null pointer passed as argument 1, " \
263 "which is declared to never be null", bufferLog) &&
264 CheckUBSanLog("napi_init.cpp:246:50", bufferLog) &&
265 CheckUBSanLog("note: nonnull attribute specified here", bufferLog);
266 int checkRes = findUBSanLog ? 1 : 0;
267 napi_value result = nullptr;
268 napi_create_int32(env, checkRes, &result);
269 return result;
270 }
271
272 // To detect the creation of null references and null pointer dereferences.
273 // If the compiler finds a pointer dereference, it treats that pointer as nonnull.
274 // As a result, the optimizer may remove null equality checks for dereferenced pointers.
Foo1(int * x)275 __attribute__((optnone)) int& Foo1(int *x)
276 {
277 return *(int *)x; // deliberately use of a null pointer to trigger the undefined behavior of null
278 }
279
NullSanitize(napi_env env,napi_callback_info info)280 __attribute__((optnone)) static napi_value NullSanitize(napi_env env, napi_callback_info info)
281 {
282 size_t argc = 1;
283 napi_value args[1] = {nullptr};
284 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
285 int status;
286 int pid = fork();
287 int checkRes = 0;
288 if (pid == -1) {
289 napi_value result = nullptr;
290 napi_create_int32(env, checkRes, &result);
291 } else if (pid == 0) {
292 // deliberately convert in C-style cast to trigger UBSan check
293 int* arr[3] = {nullptr, (int *)malloc(4), nullptr};
294 int param;
295 napi_get_value_int32(env, args[0], ¶m);
296 Foo1(arr[param]);
297 exit(0);
298 } else {
299 wait(&status);
300 }
301 std::string bufferLog = GetBuffer(pid);
302 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:277:12", bufferLog) &&
303 CheckUBSanLog("runtime error: reference binding to null pointer of type 'int'", bufferLog);
304 checkRes = findUBSanLog ? 1 : 0;
305 napi_value result = nullptr;
306 napi_create_int32(env, checkRes, &result);
307 return result;
308 }
309
310 // To detect pointer casts when the size of the source type
311 // is less than the size of the destination type.
312 class Base {
313 };
314 class Derived : public Base {
315 public:
Derived()316 Derived() : pad2(1) {}
317 int pad2;
318 };
319
320 // To detect the pointer arithmetic which overflows,
321 // or where either the old or new pointer value is a null pointer
Foo2(int i)322 __attribute__((optnone)) int* Foo2(int i)
323 {
324 int *p = reinterpret_cast<int *>(UINTPTR_MAX);
325 return p + i;
326 }
327
PointerOverflow(napi_env env,napi_callback_info info)328 __attribute__((optnone)) static napi_value PointerOverflow(napi_env env, napi_callback_info info)
329 {
330 size_t argc = 1;
331 napi_value args[1] = {nullptr};
332 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
333 int status;
334 int pid = fork();
335 int checkRes = 0;
336 if (pid == -1) {
337 napi_value result = nullptr;
338 napi_create_int32(env, checkRes, &result);
339 } else if (pid == 0) {
340 int param;
341 napi_get_value_int32(env, args[0], ¶m);
342 *(Foo2(param));
343 exit(0);
344 } else {
345 wait(&status);
346 }
347 std::string bufferLog = GetBuffer(pid);
348 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:325:14", bufferLog) &&
349 CheckUBSanLog("runtime error: pointer index expression with base 0xffffffffffffffff " \
350 "overflowed to 0x00000000000f", bufferLog);
351 checkRes = findUBSanLog ? 1 : 0;
352 napi_value result = nullptr;
353 napi_create_int32(env, checkRes, &result);
354 return result;
355 }
356
357 // To detect when a function with the returns_nonnull attribute returns null.
Foo3(int * p)358 __attribute__((nonnull)) int *Foo3(int *p)
359 {
360 return p;
361 }
362
ReturnNonnullAttribute(napi_env env,napi_callback_info info)363 __attribute__((optnone)) static napi_value ReturnNonnullAttribute(napi_env env, napi_callback_info info)
364 {
365 size_t argc = 1;
366 napi_value args[1] = {nullptr};
367 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
368 // deliberately convert in C-style cast to trigger UBSan check
369 int* arr[3] = {nullptr, (int *)malloc(sizeof(int)), nullptr};
370 int param;
371 napi_get_value_int32(env, args[0], ¶m);
372 Foo3(arr[param]);
373 std::string bufferLog = GetBuffer(getpid());
374 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:372:10", bufferLog) &&
375 CheckUBSanLog("runtime error: null pointer passed as argument 1, " \
376 "which is declared to never be null", bufferLog) &&
377 CheckUBSanLog("napi_init.cpp:358:16", bufferLog) &&
378 CheckUBSanLog("note: nonnull attribute specified here", bufferLog);
379 int checkRes = findUBSanLog ? 1 : 0;
380 napi_value result = nullptr;
381 napi_create_int32(env, checkRes, &result);
382 return result;
383 }
384
385 // To detect bitwise shifts with invalid shift amounts and shifts that might overflow
386 // shift-base is to check only left-hand side of shift operation
ShiftBase(napi_env env,napi_callback_info info)387 __attribute__((optnone)) static napi_value ShiftBase(napi_env env, napi_callback_info info)
388 {
389 size_t argc = 1;
390 napi_value args[1] = {nullptr};
391 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
392 int param;
393 napi_get_value_int32(env, args[0], ¶m);
394 int x = 1;
395 int res = x << param;
396 std::string bufferLog = GetBuffer(getpid());
397 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:395:17", bufferLog) &&
398 CheckUBSanLog("runtime error: shift exponent 32 is too large for 32-bit type 'int'", bufferLog);
399 int checkRes = findUBSanLog ? 1 : 0;
400 napi_value result = nullptr;
401 napi_create_int32(env, checkRes, &result);
402 return result;
403 }
404
405 // To detect bitwise shifts with invalid shift amounts and shifts that might overflow
406 // shift-base is to check only left-hand negative
ShiftBaseNegative(napi_env env,napi_callback_info info)407 __attribute__((optnone)) static napi_value ShiftBaseNegative(napi_env env, napi_callback_info info)
408 {
409 size_t argc = 1;
410 napi_value args[1] = {nullptr};
411 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
412 int param;
413 napi_get_value_int32(env, args[0], ¶m);
414 int x = 1;
415 int res = x << param;
416 std::string bufferLog = GetBuffer(getpid());
417 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:415:17", bufferLog) &&
418 CheckUBSanLog("runtime error: shift exponent -2 is negative", bufferLog);
419 int checkRes = findUBSanLog ? 1 : 0;
420 napi_value result = nullptr;
421 napi_create_int32(env, checkRes, &result);
422 return result;
423 }
424
425 // shift-exponent is to check only right-hand side of shift operation
ShiftExponent(napi_env env,napi_callback_info info)426 __attribute__((optnone)) static napi_value ShiftExponent(napi_env env, napi_callback_info info)
427 {
428 size_t argc = 1;
429 napi_value args[1] = {nullptr};
430 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
431 int param;
432 napi_get_value_int32(env, args[0], ¶m);
433 int x = -1;
434 int res = x >> param;
435 std::string bufferLog = GetBuffer(getpid());
436 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:434:17", bufferLog) &&
437 CheckUBSanLog("runtime error: shift exponent 32 is too large for 32-bit type 'int'", bufferLog);
438 int checkRes = findUBSanLog ? 1 : 0;
439 napi_value result = nullptr;
440 napi_create_int32(env, checkRes, &result);
441 return result;
442 }
443
444 // shift-exponent is to check only right-hand side of shift operation negative
ShiftExponentNegative(napi_env env,napi_callback_info info)445 __attribute__((optnone)) static napi_value ShiftExponentNegative(napi_env env, napi_callback_info info)
446 {
447 size_t argc = 1;
448 napi_value args[1] = {nullptr};
449 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
450 int param;
451 napi_get_value_int32(env, args[0], ¶m);
452 int x = 1;
453 int res = x >> param;
454 std::string bufferLog = GetBuffer(getpid());
455 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:453:17", bufferLog) &&
456 CheckUBSanLog("runtime error: shift exponent -2 is negative", bufferLog);
457 int checkRes = findUBSanLog ? 1 : 0;
458 napi_value result = nullptr;
459 napi_create_int32(env, checkRes, &result);
460 return result;
461 }
462
463 // shift-exponent is to check only right-hand side of shift operation bound
ShiftExponentBound(napi_env env,napi_callback_info info)464 __attribute__((optnone)) static napi_value ShiftExponentBound(napi_env env, napi_callback_info info)
465 {
466 size_t argc = 1;
467 napi_value args[1] = {nullptr};
468 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
469 int param;
470 napi_get_value_int32(env, args[0], ¶m);
471 int x = 1;
472 int res = x >> param;
473 std::string bufferLog = GetBuffer(getpid());
474 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:472:17", bufferLog) &&
475 CheckUBSanLog("runtime error: shift exponent 32 is too large for 32-bit type 'int'", bufferLog);
476 int checkRes = findUBSanLog ? 1 : 0;
477 napi_value result = nullptr;
478 napi_create_int32(env, checkRes, &result);
479 return result;
480 }
481
482 // To detect accesses to a Boolean variable when its value isn’t true or false.
483 // This problem can occur when using an integer or pointer without an appropriate cast.
UndefinedBool(napi_env env,napi_callback_info info)484 __attribute__((optnone)) static napi_value UndefinedBool(napi_env env, napi_callback_info info)
485 {
486 int res = -1;
487 // deliberately convert from integer to bool
488 // to trigger the undefined behavior of float-cast-overflow
489 int x = 42;
490 bool *predicate = reinterpret_cast<bool *>(&x);
491 if (*predicate) {
492 res = 1;
493 } else {
494 res = 0;
495 }
496 std::string bufferLog = GetBuffer(getpid());
497 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:491:9", bufferLog) &&
498 CheckUBSanLog("runtime error: load of value 42, which is not a valid value for type 'bool'", bufferLog);
499 int checkRes = findUBSanLog ? 1 : 0;
500 napi_value result = nullptr;
501 napi_create_int32(env, checkRes, &result);
502 return result;
503 }
504
505 // To detect negative array bounds.
VlaBound(napi_env env,napi_callback_info info)506 __attribute__((optnone)) static napi_value VlaBound(napi_env env, napi_callback_info info)
507 {
508 size_t argc = 1;
509 napi_value args[1] = {nullptr};
510 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
511 int status;
512 int pid = fork();
513 int checkRes = 0;
514 if (pid == -1) {
515 napi_value result = nullptr;
516 napi_create_int32(env, checkRes, &result);
517 } else if (pid == 0) {
518 int param;
519 napi_get_value_int32(env, args[0], ¶m);
520 int vla[param];
521 exit(0);
522 } else {
523 wait(&status);
524 }
525 std::string bufferLog = GetBuffer(pid);
526 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:520:17", bufferLog) &&
527 CheckUBSanLog("runtime error: variable length array bound evaluates to non-positive value -1", bufferLog);
528 checkRes = findUBSanLog ? 1 : 0;
529 napi_value result = nullptr;
530 napi_create_int32(env, checkRes, &result);
531 return result;
532 }
533
534 // funcation unreachable
Unreachable(napi_env env,napi_callback_info info)535 __attribute__((optnone)) static napi_value Unreachable(napi_env env, napi_callback_info info)
536 {
537 int status;
538 int pid = fork();
539 int checkRes = 0;
540 if (pid == -1) {
541 napi_value result = nullptr;
542 napi_create_int32(env, checkRes, &result);
543 } else if (pid == 0) {
544 __builtin_unreachable();
545 } else {
546 wait(&status);
547 }
548 std::string bufferLog = GetBuffer(pid);
549 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:544:9", bufferLog) &&
550 CheckUBSanLog("runtime error: execution reached an unreachable program point", bufferLog);
551 checkRes = findUBSanLog ? 1 : 0;
552 napi_value result = nullptr;
553 napi_create_int32(env, checkRes, &result);
554 return result;
555 }
556
ReturnNull(int a)557 __attribute__((optnone)) int ReturnNull(int a) {}
558 // funcation no return
NoReturn(napi_env env,napi_callback_info info)559 __attribute__((optnone)) static napi_value NoReturn(napi_env env, napi_callback_info info)
560 {
561 size_t argc = 1;
562 napi_value args[1] = {nullptr};
563 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
564 int status;
565 int pid = fork();
566 int checkRes = 0;
567 if (pid == -1) {
568 napi_value result = nullptr;
569 napi_create_int32(env, checkRes, &result);
570 } else if (pid == 0) {
571 int param;
572 napi_get_value_int32(env, args[0], ¶m);
573 ReturnNull(param);
574 } else {
575 wait(&status);
576 }
577 std::string bufferLog = GetBuffer(pid);
578 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:557:30", bufferLog) &&
579 CheckUBSanLog("runtime error: execution reached the end of a value-returning function without returning a value",
580 bufferLog);
581 checkRes = findUBSanLog ? 1 : 0;
582 napi_value result = nullptr;
583 napi_create_int32(env, checkRes, &result);
584 return result;
585 }
586
ShiftBaseIntMax(napi_env env,napi_callback_info info)587 __attribute__((optnone)) static napi_value ShiftBaseIntMax(napi_env env, napi_callback_info info)
588 {
589 size_t argc = 1;
590 napi_value args[1] = {nullptr};
591 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
592 int param;
593 napi_get_value_int32(env, args[0], ¶m);
594 int x = -1;
595 int res = param << x;
596 std::string bufferLog = GetBuffer(getpid());
597 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:595:21", bufferLog) &&
598 CheckUBSanLog("runtime error: shift exponent -1 is negative", bufferLog);
599 int checkRes = findUBSanLog ? 1 : 0;
600 napi_value result = nullptr;
601 napi_create_int32(env, checkRes, &result);
602 return result;
603 }
604
ShiftBaseIntMin(napi_env env,napi_callback_info info)605 __attribute__((optnone)) static napi_value ShiftBaseIntMin(napi_env env, napi_callback_info info)
606 {
607 size_t argc = 1;
608 napi_value args[1] = {nullptr};
609 napi_get_cb_info(env, info, &argc, args, nullptr, nullptr);
610 int param;
611 napi_get_value_int32(env, args[0], ¶m);
612 int x = 1;
613 int res = param << x;
614 std::string bufferLog = GetBuffer(getpid());
615 bool findUBSanLog = CheckUBSanLog("napi_init.cpp:613:21", bufferLog) &&
616 CheckUBSanLog("runtime error: left shift of negative value -2147483648", bufferLog);
617 int checkRes = findUBSanLog ? 1 : 0;
618 napi_value result = nullptr;
619 napi_create_int32(env, checkRes, &result);
620 return result;
621 }
622
623 EXTERN_C_START
Init(napi_env env,napi_value exports)624 static napi_value Init(napi_env env, napi_value exports)
625 {
626 napi_property_descriptor desc[] = {
627 { "misAlign", nullptr, MisAlign, nullptr, nullptr, nullptr, napi_default, nullptr },
628 { "bounds", nullptr, Bounds, nullptr, nullptr, nullptr, napi_default, nullptr },
629 { "integerDivBy0", nullptr, IntegerDivBy0, nullptr, nullptr, nullptr, napi_default, nullptr },
630 { "enumSan", nullptr, EnumSan, nullptr, nullptr, nullptr, napi_default, nullptr },
631 { "floatCastOverflow", nullptr, FloatCastOverflow, nullptr, nullptr, nullptr, napi_default, nullptr },
632 { "signedIntegerOverflow", nullptr, SignedIntegerOverflow, nullptr, nullptr, nullptr, napi_default, nullptr },
633 { "vptrCheck", nullptr, VptrCheck, nullptr, nullptr, nullptr, napi_default, nullptr },
634 { "nonnullAttribute", nullptr, NonnullAttribute, nullptr, nullptr, nullptr, napi_default, nullptr },
635 { "nullSanitize", nullptr, NullSanitize, nullptr, nullptr, nullptr, napi_default, nullptr },
636 { "pointerOverflow", nullptr, PointerOverflow, nullptr, nullptr, nullptr, napi_default, nullptr },
637 { "returnNonnullAttribute", nullptr, ReturnNonnullAttribute, nullptr, nullptr, nullptr, napi_default, nullptr },
638 { "shiftBase", nullptr, ShiftBase, nullptr, nullptr, nullptr, napi_default, nullptr },
639 { "shiftBaseNegative", nullptr, ShiftBaseNegative, nullptr, nullptr, nullptr, napi_default, nullptr },
640 { "shiftExponent", nullptr, ShiftExponent, nullptr, nullptr, nullptr, napi_default, nullptr },
641 { "shiftExponentNegative", nullptr, ShiftExponentNegative, nullptr, nullptr, nullptr, napi_default, nullptr },
642 { "shiftExponentBound", nullptr, ShiftExponentBound, nullptr, nullptr, nullptr, napi_default, nullptr },
643 { "undefinedBool", nullptr, UndefinedBool, nullptr, nullptr, nullptr, napi_default, nullptr },
644 { "vlaBound", nullptr, VlaBound, nullptr, nullptr, nullptr, napi_default, nullptr },
645 { "unreachable", nullptr, Unreachable, nullptr, nullptr, nullptr, napi_default, nullptr },
646 { "noReturn", nullptr, NoReturn, nullptr, nullptr, nullptr, napi_default, nullptr },
647 { "shiftBaseIntMax", nullptr, ShiftBaseIntMax, nullptr, nullptr, nullptr, napi_default, nullptr },
648 { "shiftBaseIntMin", nullptr, ShiftBaseIntMin, nullptr, nullptr, nullptr, napi_default, nullptr }
649 };
650 napi_define_properties(env, exports, sizeof(desc) / sizeof(desc[0]), desc);
651 return exports;
652 }
653 EXTERN_C_END
654
655 static napi_module demoModule = {
656 .nm_version = 1,
657 .nm_flags = 0,
658 .nm_filename = nullptr,
659 .nm_register_func = Init,
660 .nm_modname = "entry",
661 .nm_priv = ((void*)0),
662 .reserved = { 0 },
663 };
664
RegisterEntryModule(void)665 extern "C" __attribute__((constructor)) void RegisterEntryModule(void)
666 {
667 napi_module_register(&demoModule);
668 }
669