Coverage Report

Created: 2025-10-10 06:11

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/moddable/xs/tools/xstFuzz.c
Line
Count
Source
1
/*
2
 * Copyright (c) 2016-2025  Moddable Tech, Inc.
3
 *
4
 *   This file is part of the Moddable SDK Tools.
5
 * 
6
 *   The Moddable SDK Tools is free software: you can redistribute it and/or modify
7
 *   it under the terms of the GNU General Public License as published by
8
 *   the Free Software Foundation, either version 3 of the License, or
9
 *   (at your option) any later version.
10
 * 
11
 *   The Moddable SDK Tools is distributed in the hope that it will be useful,
12
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
 *   GNU General Public License for more details.
15
 * 
16
 *   You should have received a copy of the GNU General Public License
17
 *   along with the Moddable SDK Tools.  If not, see <http://www.gnu.org/licenses/>.
18
 *
19
 */
20
21
#include "xsAll.h"
22
#include "xsScript.h"
23
#include "xs.h"
24
25
extern int fuzz(int argc, char* argv[]);
26
extern void fx_print(xsMachine* the);
27
extern void fxBuildAgent(xsMachine* the);
28
extern void fxBuildFuzz(xsMachine* the);
29
extern void fxRunLoop(txMachine* the);
30
extern void fxRunModuleFile(txMachine* the, txString path);
31
extern void fxRunProgramFile(txMachine* the, txString path, txUnsigned flags);
32
33
#if OSSFUZZ
34
static int fuzz_oss(const uint8_t *Data, size_t script_size);
35
#endif
36
37
#if FUZZING
38
static void fx_fillBuffer(txMachine *the);
39
static void fx_fuzz_gc(xsMachine* the);
40
static void fx_fuzz_doMarshall(xsMachine* the);
41
#if OSSFUZZ
42
static void fx_nop(xsMachine *the);
43
static void fx_assert_throws(xsMachine *the);
44
#endif
45
#if FUZZILLI
46
static void fx_memoryFail(txMachine *the);
47
static void fx_fuzzilli(xsMachine* the);
48
#endif
49
extern int gxStress;
50
int gxMemoryFail;   // not thread safe
51
#endif
52
/* native memory stress */
53
54
void fxBuildFuzz(xsMachine* the) 
55
0
{
56
0
#if FUZZING
57
0
  xsResult = xsNewHostFunction(fx_fuzz_gc, 0);
58
0
  xsSet(xsGlobal, xsID("gc"), xsResult);
59
0
  xsResult = xsNewHostFunction(fx_fillBuffer, 2);
60
0
  xsSet(xsGlobal, xsID("fillBuffer"), xsResult);
61
0
  xsResult = xsNewHostFunction(fx_fuzz_doMarshall, 1);
62
0
  xsSet(xsGlobal, xsID("doMarshall"), xsResult);
63
#if FUZZILLI
64
  xsResult = xsNewHostFunction(fx_memoryFail, 1);
65
  xsSet(xsGlobal, xsID("memoryFail"), xsResult);
66
  xsResult = xsNewHostFunction(fx_fuzzilli, 2);
67
  xsSet(xsGlobal, xsID("fuzzilli"), xsResult);
68
#endif
69
70
0
  xsResult = xsNewHostFunction(fx_petrify, 1);
71
0
  xsDefine(xsGlobal, xsID("petrify"), xsResult, xsDontEnum);
72
0
  xsResult = xsNewHostFunction(fx_mutabilities, 1);
73
0
  xsDefine(xsGlobal, xsID("mutabilities"), xsResult, xsDontEnum);
74
75
0
  gxStress = 0;
76
0
  gxMemoryFail = 0;
77
0
#endif
78
0
}
79
80
#if OSSFUZZ
81
6.41k
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
82
6.41k
    fuzz_oss(Data, Size);
83
6.41k
    return 0;
84
6.41k
}
85
#endif
86
87
#if FUZZING
88
89
// oss-fuzz limits to 2.5 GB, so 2 GB here to be comfortably under that
90
//#define mxXSMemoryLimit 0x80000000
91
92
#if mxXSMemoryLimit
93
94
struct sxMemoryBlock {
95
  struct sxMemoryBlock  *next;
96
  struct sxMemoryBlock  *prev;
97
  struct sxMemoryBlock  *address;
98
  size_t          size;
99
};
100
typedef struct sxMemoryBlock txMemoryBlock;
101
102
0
#define kMemoryBlockCount (256)    // update hashAddress if this is changed
103
static txMemoryBlock *gBlocks[kMemoryBlockCount];
104
static size_t gBlocksSize = 0;
105
106
static uint8_t hashAddress(void *addr)
107
4.85M
{
108
4.85M
  txU8 sum = (uintptr_t)addr;
109
110
4.85M
  sum = (~sum) + (sum << 18); // sum = (sum << 18) - sum - 1;
111
4.85M
  sum = sum ^ (sum >> 31);
112
4.85M
  sum = sum * 21; // sum = (sum + (sum << 2)) + (sum << 4);
113
4.85M
  sum = sum ^ (sum >> 11);
114
4.85M
  sum = sum + (sum << 6);
115
4.85M
  sum = sum ^ (sum >> 22);
116
117
4.85M
  return (uint8_t)sum;
118
4.85M
}
119
120
9.71M
#define kBlockOverhead (64)
121
122
static txMutex gLinkMemoryMutex;
123
124
static void linkMemoryBlock(void *address, size_t size)
125
2.42M
{
126
2.42M
  static uint8_t first = 1;
127
2.42M
  if (first) {
128
1
    first = 0;
129
1
    fxCreateMutex(&gLinkMemoryMutex);
130
1
  }
131
2.42M
  uint8_t index = hashAddress(address);
132
2.42M
  txMemoryBlock *block = malloc(sizeof(txMemoryBlock));   // assuming this will never fail (nearly true)
133
134
2.42M
  block->address = address;
135
2.42M
  block->prev = C_NULL;
136
2.42M
  block->size = size;
137
138
2.42M
    fxLockMutex(&gLinkMemoryMutex);
139
140
2.42M
  block->next = gBlocks[index];
141
2.42M
  if (gBlocks[index])
142
57.0k
    gBlocks[index]->prev = block;
143
2.42M
  gBlocks[index] = block;
144
  
145
2.42M
  gBlocksSize += (size + kBlockOverhead) + (sizeof(txMemoryBlock) + kBlockOverhead);
146
147
2.42M
    fxUnlockMutex(&gLinkMemoryMutex);
148
2.42M
}
149
150
static void unlinkMemoryBlock(void *address)
151
2.42M
{
152
2.42M
  uint8_t index = hashAddress(address);
153
154
2.42M
    fxLockMutex(&gLinkMemoryMutex);
155
2.42M
  txMemoryBlock *block = gBlocks[index];
156
2.43M
  while (block && (block->address != address))
157
2.92k
    block = block->next;
158
159
2.42M
  if (block->next)
160
54.2k
    block->next->prev = block->prev;
161
162
2.42M
  if (block->prev)
163
2.89k
    block->prev->next = block->next;
164
2.42M
  else
165
2.42M
    gBlocks[index] = block->next;
166
167
2.42M
  gBlocksSize -= (block->size + kBlockOverhead) + (sizeof(txMemoryBlock) + kBlockOverhead);
168
169
2.42M
    fxUnlockMutex(&gLinkMemoryMutex);
170
171
2.42M
  free(block);
172
2.42M
}
173
174
static size_t getMemoryBlockSize(void *address)
175
157
{
176
157
  uint8_t index = hashAddress(address);
177
157
    fxLockMutex(&gLinkMemoryMutex);
178
157
  txMemoryBlock *block = gBlocks[index];
179
160
  while (block && (block->address != address))
180
3
    block = block->next;
181
157
  int size = block->size;
182
157
    fxUnlockMutex(&gLinkMemoryMutex);
183
157
    return size;
184
157
}
185
186
void freeMemoryBlocks(void)
187
0
{
188
0
  int i;
189
0
  for (i = 0; i < kMemoryBlockCount; i++) {
190
0
    while (gBlocks[i])
191
0
      fxMemFree(gBlocks[i]->address);
192
0
  }
193
0
}
194
195
#if mxNoChunks
196
void *fxMemMalloc_noforcefail(size_t size)
197
{
198
  if ((size + gBlocksSize) > mxXSMemoryLimit)
199
    return NULL;
200
201
  void *result = malloc(size);
202
  linkMemoryBlock(result, size);
203
  return result;
204
}
205
#endif
206
207
void *fxMemMalloc(size_t size)
208
2.41M
{
209
2.41M
  if (gxMemoryFail && !--gxMemoryFail)
210
0
    return NULL;
211
212
2.41M
  if ((size + gBlocksSize) > mxXSMemoryLimit)
213
0
    return NULL;
214
215
2.41M
  void *result = malloc(size);
216
2.41M
  linkMemoryBlock(result, size);
217
  
218
2.41M
  return result;
219
2.41M
}
220
221
void *fxMemCalloc(size_t a, size_t b)
222
12.8k
{
223
12.8k
  if (gxMemoryFail && !--gxMemoryFail)
224
0
    return NULL;
225
226
12.8k
  size_t size = a * b;
227
12.8k
  if ((size + gBlocksSize) > mxXSMemoryLimit)
228
0
    return NULL;
229
230
12.8k
  void *result = calloc(a, b);
231
12.8k
  linkMemoryBlock(result, size);
232
233
12.8k
  return result;
234
12.8k
}
235
236
void *fxMemRealloc(void *a, size_t b)
237
157
{
238
157
  if (gxMemoryFail && !--gxMemoryFail)
239
0
    return NULL;
240
 
241
157
  if ((b - getMemoryBlockSize(a) + gBlocksSize) > mxXSMemoryLimit)
242
0
    return NULL;
243
244
157
  unlinkMemoryBlock(a);
245
157
  a = realloc(a, b);
246
157
  linkMemoryBlock(a, b);
247
  
248
157
  return a;
249
157
}
250
251
void fxMemFree(void *m)
252
2.42M
{
253
2.42M
  unlinkMemoryBlock(m);
254
2.42M
  free(m);
255
2.42M
}
256
257
#else // 0 == mxXSMemoryLimit
258
259
#if mxNoChunks
260
void *fxMemMalloc_noforcefail(size_t size)
261
{
262
  return malloc(size);
263
}
264
#endif
265
266
void *fxMemMalloc(size_t size)
267
{
268
  if (gxMemoryFail && !--gxMemoryFail)
269
    return NULL;
270
271
  return malloc(size);
272
}
273
274
void *fxMemCalloc(size_t a, size_t b)
275
{
276
  if (gxMemoryFail && !--gxMemoryFail)
277
    return NULL;
278
279
  return calloc(a, b);
280
}
281
282
void *fxMemRealloc(void *a, size_t b)
283
{
284
  if (gxMemoryFail && !--gxMemoryFail)
285
    return NULL;
286
 
287
  return realloc(a, b);
288
}
289
290
void fxMemFree(void *m)
291
{
292
  free(m);
293
}
294
295
#endif // mxXSMemoryLimit
296
297
#endif  // FUZZING
298
299
/* FUZZILLI */
300
301
#if FUZZILLI
302
#include <stdint.h>
303
#include <sys/mman.h>
304
#include <sys/stat.h>
305
#include <fcntl.h>
306
#include <assert.h>
307
308
#define SHM_SIZE 0x100000
309
#define MAX_EDGES ((SHM_SIZE - 4) * 8)
310
311
struct shmem_data {
312
  uint32_t num_edges;
313
  unsigned char edges[];
314
};
315
316
struct shmem_data* __shmem;
317
uint32_t *__edges_start, *__edges_stop;
318
319
void __sanitizer_cov_reset_edgeguards()
320
{
321
  uint64_t N = 0;
322
  for (uint32_t *x = __edges_start; x < __edges_stop && N < MAX_EDGES; x++)
323
    *x = ++N;
324
}
325
326
void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop)
327
{
328
  // Avoid duplicate initialization
329
  if (start == stop || *start)
330
    return;
331
332
  if (__edges_start != NULL || __edges_stop != NULL) {
333
    fprintf(stderr, "Coverage instrumentation is only supported for a single module\n");
334
    c_exit(-1);
335
  }
336
337
  __edges_start = start;
338
  __edges_stop = stop;
339
340
  // Map the shared memory region
341
  const char* shm_key = getenv("SHM_ID");
342
  if (!shm_key) {
343
    puts("[COV] no shared memory bitmap available, skipping");
344
    __shmem = (struct shmem_data*) malloc(SHM_SIZE);
345
  } else {
346
    int fd = shm_open(shm_key, O_RDWR, S_IREAD | S_IWRITE);
347
    if (fd <= -1) {
348
      fprintf(stderr, "Failed to open shared memory region: %s\n", strerror(errno));
349
      c_exit(-1);
350
    }
351
352
    __shmem = (struct shmem_data*) mmap(0, SHM_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
353
    if (__shmem == MAP_FAILED) {
354
      fprintf(stderr, "Failed to mmap shared memory region\n");
355
      c_exit(-1);
356
    }
357
  }
358
359
  __sanitizer_cov_reset_edgeguards();
360
361
  __shmem->num_edges = stop - start;
362
  printf("[COV] edge counters initialized. Shared memory: %s with %u edges\n", shm_key, __shmem->num_edges);
363
}
364
365
void __sanitizer_cov_trace_pc_guard(uint32_t *guard)
366
{
367
  // There's a small race condition here: if this function executes in two threads for the same
368
  // edge at the same time, the first thread might disable the edge (by setting the guard to zero)
369
  // before the second thread fetches the guard value (and thus the index). However, our
370
  // instrumentation ignores the first edge (see libcoverage.c) and so the race is unproblematic.
371
  uint32_t index = *guard;
372
  // If this function is called before coverage instrumentation is properly initialized we want to return early.
373
  if (!index) return;
374
  __shmem->edges[index / 8] |= 1 << (index % 8);
375
  *guard = 0;
376
}
377
378
#define REPRL_CRFD 100
379
#define REPRL_CWFD 101
380
#define REPRL_DRFD 102
381
#define REPRL_DWFD 103
382
383
void fx_fuzzilli(xsMachine* the)
384
{
385
  const char* str = xsToString(xsArg(0));
386
  if (!strcmp(str, "FUZZILLI_CRASH")) {
387
    switch (xsToInteger(xsArg(1))) {
388
      case 0:
389
        // check crash
390
        *((volatile char *)0) = 0;
391
        break;
392
      case 1: {
393
        // check sanitizer
394
        // this code is so buggy its bound to trip
395
        // different sanitizers
396
        size_t s = -1;
397
#pragma GCC diagnostic push
398
#pragma GCC diagnostic ignored "-Wunused-variable"
399
        txSize txs = s + 1;
400
#pragma GCC diagnostic pop
401
        char buf[2];
402
#pragma GCC diagnostic push
403
#pragma GCC diagnostic ignored "-Wincompatible-pointer-types"
404
        char* bufptr = &buf;
405
#pragma GCC diagnostic pop
406
        bufptr[4] = (buf[0] == buf[1]) ? 0 : 1;
407
        *((volatile char *)0) = 0;
408
409
        // check ASAN
410
        char *data = malloc(64);
411
        free(data);
412
        data[0]++;
413
        } break;
414
      case 2:
415
        // check assert
416
        assert(0);
417
        break;
418
    }
419
  }
420
  else if (!strcmp(str, "FUZZILLI_PRINT")) {
421
    const char* print_str = xsToString(xsArg(1));
422
    FILE* fzliout = fdopen(REPRL_DWFD, "w");
423
    if (!fzliout) {
424
      fprintf(stderr, "Fuzzer output channel not available, printing to stdout instead\n");
425
      fzliout = stdout;
426
    }
427
    fprintf(fzliout, "%s\n", print_str);
428
    fflush(fzliout);
429
  }
430
}
431
432
#ifdef mxMetering
433
static xsBooleanValue xsAlwaysWithinComputeLimit(xsMachine* machine, uint64_t index)
434
{
435
  return 1;
436
}
437
#endif
438
439
int fuzz(int argc, char* argv[])
440
{
441
  char helo[] = "HELO";
442
  if (4 != write(REPRL_CWFD, helo, 4)) {
443
    fprintf(stderr, "Error writing HELO\n");
444
    c_exit(-1);
445
  }
446
  if (4 != read(REPRL_CRFD, helo, 4)) {
447
    fprintf(stderr, "Error reading HELO\n");
448
    c_exit(-1);
449
  }
450
  if (0 != memcmp(helo, "HELO", 4)) {
451
    fprintf(stderr, "Invalid response from parent\n");
452
    c_exit(-1);
453
  }
454
  xsCreation _creation = {
455
    1 * 1024 * 1024,  /* initialChunkSize */
456
    1 * 1024 * 1024,  /* incrementalChunkSize */
457
    32768,        /* initialHeapCount */
458
    32768,        /* incrementalHeapCount */
459
    64 * 1024,      /* stackCount */
460
    1024,       /* initialKeyCount */
461
    1024,       /* incrementalKeyCount */
462
    1993,         /* nameModulo */
463
    127,        /* symbolModulo */
464
    64 * 1024,      /* parserBufferSize */
465
    1993,       /* parserTableModulo */
466
  };
467
468
  while (1) {
469
    int error = 0;
470
    char *buffer = NULL;
471
472
    gxStress = 0;
473
    gxMemoryFail = 0;
474
475
    xsMachine* machine = xsCreateMachine(&_creation, "xst_fuzz", NULL);
476
    xsBeginMetering(machine, xsAlwaysWithinComputeLimit, 0);    // interval/step of zero means "never invoke callback" 
477
    {
478
    xsBeginHost(machine);
479
    {
480
      xsTry {
481
        xsVars(1);
482
483
        // hardened javascript
484
        xsResult = xsNewHostFunction(fx_harden, 1);
485
        xsDefine(xsGlobal, xsID("harden"), xsResult, xsDontEnum);
486
        xsResult = xsNewHostFunction(fx_lockdown, 0);
487
        xsDefine(xsGlobal, xsID("lockdown"), xsResult, xsDontEnum);
488
        xsResult = xsNewHostFunction(fx_petrify, 1);
489
        xsDefine(xsGlobal, xsID("petrify"), xsResult, xsDontEnum);
490
        xsResult = xsNewHostFunction(fx_mutabilities, 1);
491
        xsDefine(xsGlobal, xsID("mutabilities"), xsResult, xsDontEnum);
492
493
        // fuzzilli
494
        xsResult = xsNewHostFunction(fx_fuzzilli, 2);
495
        xsSet(xsGlobal, xsID("fuzzilli"), xsResult);
496
        xsResult = xsNewHostFunction(fx_fuzz_gc, 0);
497
        xsSet(xsGlobal, xsID("gc"), xsResult);
498
        xsResult = xsNewHostFunction(fx_print, 1);
499
        xsSet(xsGlobal, xsID("print"), xsResult);
500
        xsResult = xsNewHostFunction(fx_fillBuffer, 2);
501
        xsSet(xsGlobal, xsID("fillBuffer"), xsResult);
502
        xsResult = xsNewHostFunction(fx_fuzz_doMarshall, 1);
503
        xsSet(xsGlobal, xsID("doMarshall"), xsResult);        
504
        xsResult = xsNewHostFunction(fx_memoryFail, 1);
505
        xsSet(xsGlobal, xsID("memoryFail"), xsResult);
506
507
        // wait for the script
508
        char action[4];
509
        ssize_t nread = read(REPRL_CRFD, action, 4);
510
        fflush(0);    //@@
511
        if (nread != 4 || memcmp(action, "exec", 4) != 0) {
512
          fprintf(stderr, "Unknown action: %s\n", action);
513
          c_exit(-1);
514
        }
515
516
        size_t script_size = 0;
517
        read(REPRL_CRFD, &script_size, 8);
518
519
        ssize_t remaining = (ssize_t)script_size;
520
        buffer = (char *)malloc(script_size + 1);
521
        ssize_t rv = read(REPRL_DRFD, buffer, (size_t) remaining);
522
        if (rv <= 0) {
523
          fprintf(stderr, "Failed to load script\n");
524
          c_exit(-1);
525
        }
526
        buffer[script_size] = 0;  // required when debugger active
527
528
        // run the script
529
        txSlot* realm = mxProgram.value.reference->next->value.module.realm;
530
        txStringCStream aStream;
531
        aStream.buffer = buffer;
532
        aStream.offset = 0;
533
        aStream.size = script_size;
534
        the->script = fxParseScript(the, &aStream, fxStringCGetter, mxProgramFlag | mxDebugFlag);
535
        fxRunScript(the, the->script, mxRealmGlobal(realm), C_NULL, mxRealmClosures(realm)->value.reference, C_NULL, mxProgram.value.reference);
536
        the->script = NULL;
537
        mxPullSlot(mxResult);
538
539
        fxRunLoop(the);
540
      }
541
      xsCatch {
542
        the->script = NULL;
543
        error = 1;
544
      }
545
    }
546
    gxMemoryFail = 0;
547
    fxCheckUnhandledRejections(machine, 1);
548
    xsEndHost(machine);
549
    }
550
    xsEndMetering(machine);
551
    gxMemoryFail = 0;
552
    fxDeleteScript(machine->script);
553
    int status = (machine->exitStatus & 0xff) << 8;
554
    if (!status && error)
555
      status = XS_UNHANDLED_EXCEPTION_EXIT << 8;
556
    if (write(REPRL_CWFD, &status, 4) != 4) {
557
      fprintf(stderr, "Erroring writing return value over REPRL_CWFD\n");
558
      exit(-1);
559
    }
560
561
    xsDeleteMachine(machine);
562
563
    free(buffer);
564
565
    __sanitizer_cov_reset_edgeguards();
566
  }
567
568
569
  return 0;
570
}
571
#else
572
int fuzz(int argc, char* argv[])
573
0
{
574
0
  fprintf(stderr, "Build xst with FUZZING=1 FUZZILLI=1\n");
575
0
  return 1;
576
0
}
577
#endif 
578
#if OSSFUZZ
579
580
#if mxMetering
581
#ifndef mxFuzzMeter
582
  // highest rate for test262 corpus was 2147483800
583
  #define mxFuzzMeter (214748380)
584
#endif
585
586
static xsBooleanValue xsWithinComputeLimit(xsMachine* machine, uint64_t index)
587
0
{
588
  // may be useful to print current index for debugging
589
//  fprintf(stderr, "Current index: %u\n", index);
590
0
  if (index > mxFuzzMeter) {
591
//    fprintf(stderr, "Computation limits reached (index %u). Exiting...\n", index);
592
0
    return 0;
593
0
  }
594
0
  return 1;
595
0
}
596
#endif
597
598
extern void modInstallTextDecoder(xsMachine *the);
599
600
int fuzz_oss(const uint8_t *Data, size_t script_size)
601
6.41k
{
602
6.41k
  xsCreation _creation = {
603
6.41k
    1 * 1024 * 1024,  /* initialChunkSize */
604
6.41k
    1 * 1024 * 1024,  /* incrementalChunkSize */
605
6.41k
    32768,        /* initialHeapCount */
606
6.41k
    32768,        /* incrementalHeapCount */
607
6.41k
    64 * 1024,      /* stackCount */
608
6.41k
    1024,       /* initialKeyCount */
609
6.41k
    1024,       /* incrementalKeyCount */
610
6.41k
    1993,         /* nameModulo */
611
6.41k
    127,        /* symbolModulo */
612
6.41k
    64 * 1024,      /* parserBufferSize */
613
6.41k
    1993,       /* parserTableModulo */
614
6.41k
  };
615
6.41k
  size_t buffer_size = script_size + script_size + script_size + 1;     // (massively) over-allocate to have space if UTF-8 encoding expands (1 byte invalid byte becomes a 3-byte UTF-8 sequence)
616
6.41k
  char* buffer = (char *)malloc(buffer_size);
617
6.41k
  memcpy(buffer, Data, script_size);
618
619
6.41k
  buffer[script_size] = 0;  // required when debugger active
620
621
6.41k
  xsCreation* creation = &_creation;
622
6.41k
  xsMachine* machine;
623
6.41k
  machine = xsCreateMachine(creation, "xst_fuzz_oss", NULL);
624
625
12.8k
  xsBeginMetering(machine, xsWithinComputeLimit, 65536);
626
12.8k
  {
627
12.8k
    xsBeginHost(machine);
628
12.8k
    {
629
12.8k
      xsTry {
630
6.41k
        xsVars(2);
631
6.41k
        modInstallTextDecoder(the);
632
6.41k
        xsResult = xsArrayBuffer(buffer, script_size);
633
6.41k
        xsVar(0) = xsNew0(xsGlobal, xsID("TextDecoder"));
634
6.41k
        xsResult = xsCall1(xsVar(0), xsID("decode"), xsResult);
635
6.41k
  #ifdef OSSFUZZ_JSONPARSE
636
6.41k
        xsVar(0) = xsGet(xsGlobal, xsID("JSON"));
637
6.41k
        xsResult = xsCall1(xsVar(0), xsID("parse"), xsResult);
638
  #else
639
        xsToStringBuffer(xsResult, buffer, buffer_size);
640
641
        // hardened javascript
642
        xsResult = xsNewHostFunction(fx_harden, 1);
643
        xsDefine(xsGlobal, xsID("harden"), xsResult, xsDontEnum);
644
        xsResult = xsNewHostFunction(fx_lockdown, 0);
645
        xsDefine(xsGlobal, xsID("lockdown"), xsResult, xsDontEnum);
646
        xsResult = xsNewHostFunction(fx_petrify, 1);
647
        xsDefine(xsGlobal, xsID("petrify"), xsResult, xsDontEnum);
648
        xsResult = xsNewHostFunction(fx_mutabilities, 1);
649
        xsDefine(xsGlobal, xsID("mutabilities"), xsResult, xsDontEnum);
650
651
        xsResult = xsNewHostFunction(fx_fuzz_gc, 0);
652
        xsSet(xsGlobal, xsID("gc"), xsResult);
653
        xsResult = xsNewHostFunction(fx_print, 1);
654
        xsSet(xsGlobal, xsID("print"), xsResult);
655
656
        // test262 stubs
657
        xsVar(0) = xsNewHostFunction(fx_nop, 1);
658
        xsDefine(xsGlobal, xsID("assert"), xsVar(0), xsDontEnum);
659
        xsDefine(xsVar(0), xsID("sameValue"), xsVar(0), xsDontEnum);
660
        xsDefine(xsVar(0), xsID("notSameValue"), xsVar(0), xsDontEnum);
661
        xsVar(1) = xsNewHostFunction(fx_assert_throws, 1);
662
        xsDefine(xsVar(0), xsID("throws"), xsVar(1), xsDontEnum);
663
        
664
        txStringCStream aStream;
665
        aStream.buffer = buffer;
666
        aStream.offset = 0;
667
        aStream.size = strlen(buffer);
668
        // run script
669
        txSlot* realm = mxProgram.value.reference->next->value.module.realm;
670
        the->script = fxParseScript(the, &aStream, fxStringCGetter, mxProgramFlag | mxDebugFlag);
671
        fxRunScript(the, the->script, mxRealmGlobal(realm), C_NULL, mxRealmClosures(realm)->value.reference, C_NULL, mxProgram.value.reference);
672
        the->script = NULL;
673
        mxPullSlot(mxResult);
674
        fxRunLoop(the);
675
  #endif
676
6.41k
      }
677
6.41k
      xsCatch {
678
4.78k
        the->script = NULL;
679
4.78k
      }
680
12.8k
    }
681
12.8k
    xsEndHost(machine);
682
12.8k
  }
683
12.8k
  xsEndMetering(machine);
684
6.41k
  fxDeleteScript(machine->script);
685
6.41k
#if mxXSMemoryLimit
686
6.41k
  int exitStatus = machine->exitStatus;
687
6.41k
#endif
688
6.41k
  xsDeleteMachine(machine);
689
6.41k
  free(buffer);
690
691
6.41k
#if mxXSMemoryLimit
692
6.41k
  if ((XS_TOO_MUCH_COMPUTATION_EXIT == exitStatus) || (XS_NOT_ENOUGH_MEMORY_EXIT == exitStatus) || (XS_JAVASCRIPT_STACK_OVERFLOW_EXIT == exitStatus)|| (XS_NATIVE_STACK_OVERFLOW_EXIT == exitStatus))
693
0
    freeMemoryBlocks();   // clean-up if computation or memory limits exceeded, or stack overflow
694
6.41k
#endif
695
696
6.41k
  return 0;
697
6.41k
}
698
699
#endif 
700
701
#if FUZZING || FUZZILLI
702
703
void fx_fillBuffer(txMachine *the)
704
0
{
705
0
  xsIntegerValue seed = xsToInteger(xsArg(1));
706
0
  xsIntegerValue length = xsGetArrayBufferLength(xsArg(0)), i;
707
0
  uint8_t *buffer = xsToArrayBuffer(xsArg(0));
708
  
709
0
  for (i = 0; i < length; i++) {
710
0
    seed = (uint64_t)seed * 48271 % 0x7fffffff;
711
0
    *buffer++ = (uint8_t)seed;
712
0
  }
713
0
}
714
715
void fx_fuzz_gc(xsMachine* the)
716
0
{
717
0
  xsResult = xsInteger(gxStress);
718
719
0
  xsIntegerValue c = xsToInteger(xsArgc);
720
0
  if (!c) {
721
0
    xsCollectGarbage();
722
0
    return;
723
0
  }
724
  
725
0
  int count = xsToInteger(xsArg(0));
726
0
  gxStress = (count < 0) ? count : -count;
727
0
}
728
729
void fx_fuzz_doMarshall(xsMachine *the)
730
0
{
731
0
  char *message;
732
0
  xsIntegerValue c = xsToInteger(xsArgc);
733
0
  if (c > 0)
734
0
    message = xsMarshallAlien(xsArg(0));
735
0
  else
736
0
    message = xsMarshallAlien(xsUndefined);
737
0
  xsResult = xsDemarshallAlien(message);
738
0
  c_free(message);
739
0
}
740
741
#if OSSFUZZ
742
void fx_nop(xsMachine *the)
743
0
{
744
0
}
745
746
void fx_assert_throws(xsMachine *the)
747
0
{
748
0
  mxTry(the) {
749
0
    if (xsToInteger(xsArgc) >= 2)
750
0
      xsCallFunction0(xsArg(1), xsGlobal);
751
0
  }
752
0
  mxCatch(the) {
753
0
  }
754
0
}
755
#endif 
756
757
#if FUZZILLI
758
void fx_memoryFail(txMachine *the)
759
{
760
  xsResult = xsInteger(gxMemoryFail);
761
  if (!xsToInteger(xsArgc))
762
    return;
763
764
  int count = xsToInteger(xsArg(0));
765
  if (count < 0)
766
    xsUnknownError("invalid");
767
  gxMemoryFail = count;
768
}
769
#endif
770
771
#endif