@@ -372,33 +372,100 @@ export class FuzzedDataProvider {
372
372
* is not sufficiently long.
373
373
* @param maxLength the maximum length of the string
374
374
* @param encoding the encoding of the string
375
+ * @param printable - a boolean, which defaults to false that indicates whether consumed strings
376
+ * should be forced to contain only valid printable characters
375
377
* @returns a `string` of length between 0 and `maxLength` (inclusive)
376
378
*/
377
379
consumeString (
378
380
maxLength : number ,
379
- encoding : BufferEncoding | undefined = "ascii"
381
+ encoding : BufferEncoding | undefined = "ascii" ,
382
+ printable : boolean | undefined = false
380
383
) : string {
381
384
if ( maxLength < 0 ) throw new Error ( "maxLength must be non-negative" ) ;
385
+ let result ;
382
386
const arrayLength = Math . min ( maxLength , this . _remainingBytes ) ;
383
- const result = this . data . toString (
384
- encoding ,
385
- this . dataPtr ,
386
- this . dataPtr + arrayLength
387
- ) ;
387
+
388
+ if ( printable ) {
389
+ result = this . bufToPrintableString (
390
+ this . data ,
391
+ this . dataPtr ,
392
+ this . dataPtr + arrayLength ,
393
+ encoding
394
+ ) ;
395
+ } else {
396
+ result = this . data . toString (
397
+ encoding ,
398
+ this . dataPtr ,
399
+ this . dataPtr + arrayLength
400
+ ) ;
401
+ }
388
402
this . dataPtr += arrayLength ;
389
403
this . _remainingBytes -= arrayLength ;
390
404
return result ;
391
405
}
392
406
407
+ /**
408
+ * Wrapping subtraction function that returns a number within a set limit
409
+ * @param min is a number representing the minuend
410
+ * @param sub is a number representing the subtrahend
411
+ * @param lim sets the upper boundary
412
+ * @returns a number n with the constraint 0 <= n < lim, as long as lim >=2
413
+ */
414
+ wrappingSub ( min : number , sub : number , lim : number ) : number {
415
+ if ( lim < 2 ) {
416
+ throw new Error ( "Upper boundary should be greater than or equal to 2" ) ;
417
+ }
418
+ return ( min - sub + lim ) % lim ;
419
+ }
420
+
421
+ /**
422
+ * A simple conversion helper that yields the ASCII representaion of a character.
423
+ * @param char is a single character from a string represented as a number
424
+ * @returns a 'string' from a single character that was represented by a number
425
+ */
426
+ toAscii ( char : number ) : number {
427
+ if ( char < 32 || char > 126 ) {
428
+ char = ( this . wrappingSub ( char , 32 , 255 ) % 95 ) + 32 ;
429
+ }
430
+ return char ;
431
+ }
432
+
433
+ /**
434
+ * Helper function that converts the given string type into one that only
435
+ * contains printable characters. This conversion produces seemingly arbitrary
436
+ * (non-smart) but printable strings, IFF the entropy of the input buffer is
437
+ * high enough. Limitations are that there are collisions such that, e.g.:
438
+ * the conversion of values: `0x1`, `0x42`, and `0xa2` all yield the character `B`.
439
+ * @param buf - Buffer that contains arbitrary values
440
+ * @param min - lower bound at which processing of the provided `Buffer` shall begin
441
+ * @param max - upper bound, analogous to the lower bound
442
+ * @param encoding - a valid `BufferEncoding`.
443
+ * @returns a string that was sanitized and only contains printable characters
444
+ */
445
+ bufToPrintableString (
446
+ buf : Buffer ,
447
+ min : number ,
448
+ max : number ,
449
+ encoding : BufferEncoding
450
+ ) : string {
451
+ for ( let i = min ; i < max ; i ++ ) {
452
+ buf [ i ] = this . toAscii ( buf [ i ] ) ;
453
+ }
454
+ return buf . subarray ( min , max ) . toString ( encoding ) ;
455
+ }
456
+
393
457
/**
394
458
* Consumes the remaining bytes of the fuzzer input as a string.
395
459
* @param encoding - the encoding of the string
460
+ * @param printable - a boolean, which defaults to false that indicates whether consumed strings
461
+ * should be forced to contain only valid printable characters
396
462
* @returns a string constructed from the remaining bytes of the fuzzer input using the given encoding
397
463
*/
398
464
consumeRemainingAsString (
399
- encoding : BufferEncoding | undefined = "ascii"
465
+ encoding : BufferEncoding | undefined = "ascii" ,
466
+ printable : boolean | undefined = false
400
467
) : string {
401
- return this . consumeString ( this . _remainingBytes , encoding ) ;
468
+ return this . consumeString ( this . _remainingBytes , encoding , printable ) ;
402
469
}
403
470
404
471
/**
@@ -408,16 +475,19 @@ export class FuzzedDataProvider {
408
475
* @param maxArrayLength the maximum length of the array
409
476
* @param maxStringLength the maximum length of the strings
410
477
* @param encoding the encoding of the strings
478
+ * @param printable - a boolean, which defaults to false that indicates whether consumed strings
479
+ * should be forced to contain only valid printable characters
411
480
* @returns an array containing strings constructed from the remaining bytes of the fuzzer input using the given encoding
412
481
*/
413
482
consumeStringArray (
414
483
maxArrayLength : number ,
415
484
maxStringLength : number ,
416
- encoding : BufferEncoding | undefined = "ascii"
485
+ encoding : BufferEncoding | undefined = "ascii" ,
486
+ printable : boolean | undefined = false
417
487
) {
418
488
const strs = [ ] ;
419
489
while ( strs . length < maxArrayLength && this . remainingBytes > 0 ) {
420
- const str = this . consumeString ( maxStringLength , encoding ) ;
490
+ const str = this . consumeString ( maxStringLength , encoding , printable ) ;
421
491
if ( str ) {
422
492
strs . push ( str ) ;
423
493
}
0 commit comments