[typescript] improve harness that has hopefully no timeout issues (#10612)

These harnesses seem to run a lot better and don't need the adjusted
`--timeout` option any more from what I was able to observe. Also, the
tested API increased a bit.
This commit is contained in:
434b 2023-07-03 07:04:13 +02:00 committed by GitHub
parent fdcf8b1d21
commit 9fca6817ed
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 141 additions and 29 deletions

View File

@ -20,7 +20,6 @@ npm install
npm install --save-dev @jazzer.js/core
# Build Fuzzers.
# Fuzzing is kinda slow and a resource hog so we have to adjust the timeout and
# memory limit to satisfy libfuzzer
compile_javascript_fuzzer TypeScript fuzz_ast -i typescript --sync --timeout=30000 -- -rss_limit_mb=4096
compile_javascript_fuzzer TypeScript fuzz_compiler -i typescript --sync --timeout=30000 -- -rss_limit_mb=4096
# Fuzzing TS is a resource hog so we have to adjust the rss limit a bit
compile_javascript_fuzzer TypeScript fuzz_ast -i typescript -- -rss_limit_mb=4096
compile_javascript_fuzzer TypeScript fuzz_compiler -i typescript --sync -- -rss_limit_mb=4096

View File

@ -14,17 +14,16 @@
//
////////////////////////////////////////////////////////////////////////////////
const { FuzzedDataProvider } = require('@jazzer.js/core');
const ts = require('typescript');
const { FuzzedDataProvider } = require("@jazzer.js/core");
const ts = require("typescript");
module.exports.fuzz = function(data) {
module.exports.fuzz = async function(data) {
const provider = new FuzzedDataProvider(data);
try {
const fileName = provider.consumeString(10) + '.ts';
const fileName = provider.consumeString(10) + ".ts";
const fileContents = provider.consumeString(1000);
// Parse the source file
const sourceFile = ts.createSourceFile(
fileName,
fileContents,
@ -32,9 +31,12 @@ module.exports.fuzz = function(data) {
/*setParentNodes */ true
);
// Get the diagnostics for the source file
// Fuzzing parsing and lexing
ts.getPreEmitDiagnostics(sourceFile);
// Fuzzing type inference
ts.getTypeChecker(sourceFile);
// Consume a boolean and use it to randomly remove a node from the AST
const shouldRemoveNode = provider.consumeBoolean();
if (shouldRemoveNode) {
@ -75,13 +77,124 @@ module.exports.fuzz = function(data) {
ts.replaceNode(nodeToReplace, newNode);
}
}
// Fuzzing transformation and emit
const transformed = ts.transform(sourceFile, [/* transformation functions */]);
const transformedSourceFile = transformed.transformed[0];
// Fuzzing language features
const shouldFuzzLanguageFeature = provider.consumeBoolean();
if (shouldFuzzLanguageFeature) {
// Fuzzing classes
const classDeclaration = ts.createClassDeclaration(
/* decorators */[],
/* modifiers */[],
provider.consumeString(10),
/* typeParameters */[],
/* heritageClauses */[],
/* members */[]
);
ts.addDeclaration(sourceFile, classDeclaration);
// Fuzzing interfaces
const interfaceDeclaration = ts.createInterfaceDeclaration(
/* decorators */[],
/* modifiers */[],
provider.consumeString(10),
/* typeParameters */[],
/* heritageClauses */[],
/* members */[]
);
ts.addDeclaration(sourceFile, interfaceDeclaration);
// Fuzzing modules
const moduleDeclaration = ts.createModuleDeclaration(
/* decorators */[],
/* modifiers */[],
ts.createIdentifier(provider.consumeString(10)),
ts.createModuleBlock([]),
ts.NodeFlags.Namespace
);
ts.addDeclaration(sourceFile, moduleDeclaration);
// Fuzzing generics
const genericFunctionDeclaration = ts.createFunctionDeclaration(
/* decorators */[],
/* modifiers */[],
/* asteriskToken */ undefined,
provider.consumeString(10),
/* typeParameters */[
ts.createTypeParameterDeclaration(
ts.createIdentifier(provider.consumeString(10)),
/* constraint */ undefined,
/* defaultType */ undefined
)
],
/* parameters */[],
/* type */ undefined,
/* body */ undefined
);
ts.addDeclaration(sourceFile, genericFunctionDeclaration);
// Fuzzing decorators
const decorator = ts.createDecorator(
ts.createCall(
ts.createIdentifier(provider.consumeString(10)),
/* typeArguments */[],
/* argumentsArray */[]
)
);
ts.addDeclaration(sourceFile, decorator);
// Fuzzing async/await
const asyncFunctionDeclaration = ts.createFunctionDeclaration(
/* decorators */[],
/* modifiers */[],
/* asteriskToken */ undefined,
provider.consumeString(10),
/* typeParameters */[],
/* parameters */[],
/* type */ undefined,
ts.createBlock([
ts.createAwaitExpression(
ts.createCall(
ts.createIdentifier(provider.consumeString(10)),
/* typeArguments */[],
/* argumentsArray */[]
)
)
])
);
ts.addDeclaration(sourceFile, asyncFunctionDeclaration);
}
// Fuzzing compiler options
const compilerOptions = {
target: ts.ScriptTarget.ES5,
module: ts.ModuleKind.CommonJS,
strict: provider.consumeBoolean(),
// ...
};
const program = ts.createProgram([fileName], compilerOptions);
program.emit();
// Fuzzing API functions
const shouldFuzzApiFunction = provider.consumeBoolean();
if (shouldFuzzApiFunction) {
// Fuzzing type checking
const typeChecker = program.getTypeChecker();
const randomSymbol = typeChecker.getSymbolAtLocation(sourceFile);
typeChecker.getTypeOfSymbolAtLocation(randomSymbol, sourceFile);
// ...
}
} catch (error) {
if (!ignoredError(error)) throw error;
}
};
function ignoredError(error) {
return !!ignored.find((message) => error.message.indexOf(message) !== -1);
return !!ignored.find(message => error.message.indexOf(message) !== -1);
}
const ignored = [

View File

@ -14,28 +14,21 @@
//
////////////////////////////////////////////////////////////////////////////////
const { FuzzedDataProvider } = require('@jazzer.js/core');
const ts = require('typescript');
const { FuzzedDataProvider } = require("@jazzer.js/core");
const ts = require("typescript");
module.exports.fuzz = function(data) {
const provider = new FuzzedDataProvider(data);
try {
// Generate a random file name and path.
const fileName = provider.consumeString(10) + '.ts';
const filePath = provider.consumeString(10) + '/' + fileName;
const fileName = provider.consumeString(10) + ".ts";
const filePath = provider.consumeString(10) + "/" + fileName;
const fileContent = provider.consumeString(100);
// Generate a random file content.
const fileContent = provider.consumeString(1000);
// Create a source file from the generated file content.
const sourceFile = ts.createSourceFile(fileName, fileContent, ts.ScriptTarget.Latest);
// Parse the source file.
const result = ts.parseSourceFile(sourceFile, ts.ScriptTarget.Latest, true);
// Consume the diagnostics array generated by the parseSourceFile function.
const diagnostics = result.diagnostics.map(diagnostic => {
const _diagnostics = result.diagnostics.map(diagnostic => {
return {
message: diagnostic.messageText,
start: diagnostic.start,
@ -44,7 +37,7 @@ module.exports.fuzz = function(data) {
};
});
// Generate random inputs for additional TypeScript compiler API functions.
const program = ts.createProgram([fileName], { allowJs: true });
const printer = ts.createPrinter();
const nodes = ts.createNodeArray([sourceFile]);
@ -59,13 +52,20 @@ module.exports.fuzz = function(data) {
ts.createSymbol(ts.SymbolFlags.Type, identifier);
ts.createType(typeNode);
ts.createWatchCompilerHost([fileName], { allowJs: true }, ts.sys, ts.createSemanticDiagnosticsBuilderProgram, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
} catch (error) {
const watchCompilerHost = ts.createWatchCompilerHost([fileName], { allowJs: true }, ts.sys, ts.createSemanticDiagnosticsBuilderProgram, undefined, undefined, undefined, undefined, undefined, undefined, undefined, undefined);
program.getTypeChecker();
program.emit();
program.getTypeRoots();
ts.getParsedCommandLineOfConfigFile(fileName, {}, ts.sys).errors;
program.getDeclarationDiagnostics();
}
catch (error) {
if (!ignoredError(error)) {
throw error;
}
}
}
};
function ignoredError(error) {
return !!ignored.find((message) => error.message.indexOf(message) !== -1);