Coverage Report

Created: 2026-11-12 06:41

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