Coverage Report

Created: 2026-08-14 06:15

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