Skip to content

Commit 58053d9

Browse files
author
434b
committed
First approach to for a toggable printableStringConsumer
1 parent f989212 commit 58053d9

File tree

2 files changed

+87
-10
lines changed

2 files changed

+87
-10
lines changed

packages/core/FuzzedDataProvider.test.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,24 @@ describe("FuzzedDataProvider checks", () => {
945945
expect(strings).toContain("or si");
946946
expect(strings).toContain("t ame");
947947
});
948+
it("verifyPrintableString", () => {
949+
const data = new FuzzedDataProvider(Buffer.from(Data));
950+
const consumedStrAsArr = [...data.consumeString(1024, "ascii", true)];
951+
consumedStrAsArr.forEach((c) => {
952+
const charAsNum = c.charCodeAt(0);
953+
expect(charAsNum >= 32 && charAsNum <= 126).toBeTruthy();
954+
});
955+
});
956+
it("verifyNonPrintableString", () => {
957+
const data = new FuzzedDataProvider(Buffer.from(Data));
958+
const consumedStrAsArr = [...data.consumeString(1024)];
959+
expect(
960+
consumedStrAsArr.some((ele) => {
961+
const eleAsNum = ele.charCodeAt(0);
962+
return eleAsNum < 32 || eleAsNum > 126;
963+
})
964+
).toBeTruthy();
965+
});
948966
});
949967

950968
const Data = Buffer.from([

packages/core/FuzzedDataProvider.ts

Lines changed: 69 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -372,33 +372,89 @@ export class FuzzedDataProvider {
372372
* is not sufficiently long.
373373
* @param maxLength the maximum length of the string
374374
* @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
375377
* @returns a `string` of length between 0 and `maxLength` (inclusive)
376378
*/
377379
consumeString(
378380
maxLength: number,
379-
encoding: BufferEncoding | undefined = "ascii"
381+
encoding: BufferEncoding | undefined = "ascii",
382+
printable: boolean | undefined = false
380383
): string {
381384
if (maxLength < 0) throw new Error("maxLength must be non-negative");
385+
let result;
382386
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+
}
388402
this.dataPtr += arrayLength;
389403
this._remainingBytes -= arrayLength;
390404
return result;
391405
}
392406

407+
/**
408+
* A simple conversion helper that yields the ASCII representaion of a character.
409+
* @param char is a single character from a string represented as a number
410+
* @returns a 'string' from a single character that was represented by a number
411+
*/
412+
toAscii(char: number): number {
413+
if (char < 32 || char > 126) {
414+
const moduloInRange = (char - 32 + 256) % 256;
415+
return (moduloInRange % 95) + 32;
416+
}
417+
return char;
418+
}
419+
420+
/**
421+
* Helper function that converts the given string type into one that only
422+
* contains printable characters. This conversion produces seemingly arbitrary
423+
* (non-smart) but printable strings, IFF the entropy of the input buffer is
424+
* high enough. Limitations are that there are collisions such that, e.g.:
425+
* the conversion of values: `0x1`, `0x42`, and `0xa2` all yield the character `B`.
426+
* Elements in `buf` that are already in ASCII printable range are not undergoing
427+
* any conversion.
428+
* @param buf - Buffer that contains arbitrary values
429+
* @param min - lower bound at which processing of the provided `Buffer` shall begin
430+
* @param max - upper bound, analogous to the lower bound
431+
* @param encoding - a valid `BufferEncoding`.
432+
* @returns a string that was sanitized and only contains printable characters
433+
*/
434+
bufToPrintableString(
435+
buf: Buffer,
436+
min: number,
437+
max: number,
438+
encoding: BufferEncoding
439+
): string {
440+
for (let i = min; i < max; i++) {
441+
buf[i] = this.toAscii(buf[i]);
442+
}
443+
return buf.subarray(min, max).toString(encoding);
444+
}
445+
393446
/**
394447
* Consumes the remaining bytes of the fuzzer input as a string.
395448
* @param encoding - the encoding of the string
449+
* @param printable - a boolean, which defaults to false that indicates whether consumed strings
450+
* should be forced to contain only valid printable characters
396451
* @returns a string constructed from the remaining bytes of the fuzzer input using the given encoding
397452
*/
398453
consumeRemainingAsString(
399-
encoding: BufferEncoding | undefined = "ascii"
454+
encoding: BufferEncoding | undefined = "ascii",
455+
printable: boolean | undefined = false
400456
): string {
401-
return this.consumeString(this._remainingBytes, encoding);
457+
return this.consumeString(this._remainingBytes, encoding, printable);
402458
}
403459

404460
/**
@@ -408,16 +464,19 @@ export class FuzzedDataProvider {
408464
* @param maxArrayLength the maximum length of the array
409465
* @param maxStringLength the maximum length of the strings
410466
* @param encoding the encoding of the strings
467+
* @param printable - a boolean, which defaults to false that indicates whether consumed strings
468+
* should be forced to contain only valid printable characters
411469
* @returns an array containing strings constructed from the remaining bytes of the fuzzer input using the given encoding
412470
*/
413471
consumeStringArray(
414472
maxArrayLength: number,
415473
maxStringLength: number,
416-
encoding: BufferEncoding | undefined = "ascii"
474+
encoding: BufferEncoding | undefined = "ascii",
475+
printable: boolean | undefined = false
417476
) {
418477
const strs = [];
419478
while (strs.length < maxArrayLength && this.remainingBytes > 0) {
420-
const str = this.consumeString(maxStringLength, encoding);
479+
const str = this.consumeString(maxStringLength, encoding, printable);
421480
if (str) {
422481
strs.push(str);
423482
}

0 commit comments

Comments
 (0)