Make using natives for fuzzing more permissive

This makes creating whitelisted runtime functions more permissive on
fuzzers (when --allow-natives-for-fuzzing is passed).

- Runtime functions with too few arguments are replaced with undefined.
- Superfluous arguments are ignored.

This reduces syntax-error rate on fuzzers. Also prevents
dcheck errors when fuzzing debug builds and fuzzers use too many
arguments for runtime functions.

Bug: chromium:1044942
Change-Id: I23b45398421c50bc82d1e8bfdf019f565253db96
Reviewed-on: https://chromium-review.googlesource.com/c/v8/v8/+/2039352
Commit-Queue: Michael Achenbach <machenbach@chromium.org>
Reviewed-by: Toon Verwaest <verwaest@chromium.org>
Cr-Commit-Position: refs/heads/master@{#66202}
This commit is contained in:
Michael Achenbach 2020-02-10 14:29:33 +01:00 committed by Commit Bot
parent f925176e19
commit cf05e4ca79
3 changed files with 45 additions and 12 deletions

View File

@ -356,17 +356,16 @@ Expression* Parser::NewV8Intrinsic(const AstRawString* name,
const Runtime::Function* function =
Runtime::FunctionForName(name->raw_data(), name->length());
// Be more premissive when fuzzing. Intrinsics are not supported.
if (FLAG_allow_natives_for_fuzzing) {
return NewV8RuntimeFunctionForFuzzing(function, args, pos);
}
if (function != nullptr) {
// Check for possible name clash.
DCHECK_EQ(Context::kNotFound,
Context::IntrinsicIndexForName(name->raw_data(), name->length()));
// When fuzzing, only allow whitelisted runtime functions.
if (FLAG_allow_natives_for_fuzzing &&
!Runtime::IsWhitelistedForFuzzing(function->function_id)) {
return factory()->NewUndefinedLiteral(kNoSourcePosition);
}
// Check that the expected number of arguments are being passed.
if (function->nargs != -1 && function->nargs != args.length()) {
ReportMessage(MessageTemplate::kRuntimeWrongNumArgs);
@ -376,11 +375,6 @@ Expression* Parser::NewV8Intrinsic(const AstRawString* name,
return factory()->NewCallRuntime(function, args, pos);
}
// Intrinsics are not supported for fuzzing.
if (FLAG_allow_natives_for_fuzzing) {
return factory()->NewUndefinedLiteral(kNoSourcePosition);
}
int context_index =
Context::IntrinsicIndexForName(name->raw_data(), name->length());
@ -393,6 +387,34 @@ Expression* Parser::NewV8Intrinsic(const AstRawString* name,
return factory()->NewCallRuntime(context_index, args, pos);
}
// More permissive runtime-function creation on fuzzers.
Expression* Parser::NewV8RuntimeFunctionForFuzzing(
const Runtime::Function* function, const ScopedPtrList<Expression>& args,
int pos) {
CHECK(FLAG_allow_natives_for_fuzzing);
// Intrinsics are not supported for fuzzing. Only allow whitelisted runtime
// functions. Also prevent later errors due to too few arguments and just
// ignore this call.
if (function == nullptr ||
!Runtime::IsWhitelistedForFuzzing(function->function_id) ||
function->nargs > args.length()) {
return factory()->NewUndefinedLiteral(kNoSourcePosition);
}
// Flexible number of arguments permitted.
if (function->nargs == -1) {
return factory()->NewCallRuntime(function, args, pos);
}
// Otherwise ignore superfluous arguments.
ScopedPtrList<Expression> permissive_args(pointer_buffer());
for (int i = 0; i < function->nargs; i++) {
permissive_args.Add(args.at(i));
}
return factory()->NewCallRuntime(function, permissive_args, pos);
}
Parser::Parser(ParseInfo* info)
: ParserBase<Parser>(info->zone(), &scanner_, info->stack_limit(),
info->extension(), info->GetOrCreateAstValueFactory(),

View File

@ -833,6 +833,10 @@ class V8_EXPORT_PRIVATE Parser : public NON_EXPORTED_BASE(ParserBase<Parser>) {
Expression* NewV8Intrinsic(const AstRawString* name,
const ScopedPtrList<Expression>& args, int pos);
Expression* NewV8RuntimeFunctionForFuzzing(
const Runtime::Function* function, const ScopedPtrList<Expression>& args,
int pos);
V8_INLINE Statement* NewThrowStatement(Expression* exception, int pos) {
return factory()->NewExpressionStatement(
factory()->NewThrow(exception, pos), pos);

View File

@ -10,10 +10,17 @@
assertEquals(undefined, %GetOptimizationStatus(function (){}));
// Blacklisted intrinsics can have wrong arguments.
%GetOptimizationStatus(1, 2, 3, 4);
assertEquals(undefined, %GetOptimizationStatus(1, 2, 3, 4));
// We don't care if an intrinsic actually exists.
assertEquals(undefined, %FooBar());
// Check whitelisted intrinsic.
assertNotEquals(undefined, %IsBeingInterpreted());
// Whitelisted runtime functions with too few args are ignored.
assertEquals(undefined, %DeoptimizeFunction());
// Superfluous arguments are ignored.
%DeoptimizeFunction(function() {}, undefined);
assertNotEquals(undefined, %IsBeingInterpreted(1, 2, 3));