Commit 2d46ef23 authored by bradnelson's avatar bradnelson Committed by Commit bot

[wasm] asm.js - Check stdlib functions are valid.

Check remaining asm.js stdlib functions for validitity at instatiation.

Fail when a member is referenced, even if not used.

BUG= https://bugs.chromium.org/p/v8/issues/detail?id=4203
LOG=N
R=jpp@chromium.org,titzer@chromium.org

Review-Url: https://codereview.chromium.org/2267633002
Cr-Commit-Position: refs/heads/master@{#38796}
parent cff8e03d
...@@ -53,8 +53,28 @@ i::MaybeHandle<i::FixedArray> CompileModule( ...@@ -53,8 +53,28 @@ i::MaybeHandle<i::FixedArray> CompileModule(
return compiled_module; return compiled_module;
} }
Handle<i::Object> StdlibMathMember(i::Isolate* isolate,
Handle<JSReceiver> stdlib,
Handle<Name> name) {
Handle<i::Name> math_name(
isolate->factory()->InternalizeOneByteString(STATIC_CHAR_VECTOR("Math")));
MaybeHandle<i::Object> maybe_math = i::Object::GetProperty(stdlib, math_name);
if (maybe_math.is_null()) {
return Handle<i::Object>();
}
Handle<i::Object> math = maybe_math.ToHandleChecked();
if (!math->IsJSReceiver()) {
return Handle<i::Object>();
}
MaybeHandle<i::Object> maybe_value = i::Object::GetProperty(math, name);
if (maybe_value.is_null()) {
return Handle<i::Object>();
}
return maybe_value.ToHandleChecked();
}
bool IsStdlibMemberValid(i::Isolate* isolate, Handle<JSReceiver> stdlib, bool IsStdlibMemberValid(i::Isolate* isolate, Handle<JSReceiver> stdlib,
i::Handle<i::Object> member_id) { Handle<i::Object> member_id) {
int32_t member_kind; int32_t member_kind;
if (!member_id->ToInt32(&member_kind)) { if (!member_id->ToInt32(&member_kind)) {
UNREACHABLE(); UNREACHABLE();
...@@ -62,56 +82,81 @@ bool IsStdlibMemberValid(i::Isolate* isolate, Handle<JSReceiver> stdlib, ...@@ -62,56 +82,81 @@ bool IsStdlibMemberValid(i::Isolate* isolate, Handle<JSReceiver> stdlib,
switch (member_kind) { switch (member_kind) {
case wasm::AsmTyper::StandardMember::kNone: case wasm::AsmTyper::StandardMember::kNone:
case wasm::AsmTyper::StandardMember::kModule: case wasm::AsmTyper::StandardMember::kModule:
case wasm::AsmTyper::StandardMember::kStdlib: { case wasm::AsmTyper::StandardMember::kStdlib:
case wasm::AsmTyper::StandardMember::kHeap:
case wasm::AsmTyper::StandardMember::kFFI: {
// Nothing to check for these. // Nothing to check for these.
return true; return true;
} }
case wasm::AsmTyper::StandardMember::kNaN: { case wasm::AsmTyper::StandardMember::kInfinity: {
i::Handle<i::Name> name(isolate->factory()->InternalizeOneByteString( Handle<i::Name> name(isolate->factory()->InternalizeOneByteString(
STATIC_CHAR_VECTOR("NaN"))); STATIC_CHAR_VECTOR("Infinity")));
i::MaybeHandle<i::Object> maybe_value = MaybeHandle<i::Object> maybe_value = i::Object::GetProperty(stdlib, name);
i::Object::GetProperty(stdlib, name);
if (maybe_value.is_null()) { if (maybe_value.is_null()) {
return false; return false;
} }
i::Handle<i::Object> value = maybe_value.ToHandleChecked(); Handle<i::Object> value = maybe_value.ToHandleChecked();
if (!value->IsNaN()) { return value->IsNumber() && std::isinf(value->Number());
}
case wasm::AsmTyper::StandardMember::kNaN: {
Handle<i::Name> name(isolate->factory()->InternalizeOneByteString(
STATIC_CHAR_VECTOR("NaN")));
MaybeHandle<i::Object> maybe_value = i::Object::GetProperty(stdlib, name);
if (maybe_value.is_null()) {
return false; return false;
} }
return true; Handle<i::Object> value = maybe_value.ToHandleChecked();
return value->IsNaN();
} }
case wasm::AsmTyper::StandardMember::kHeap: #define STDLIB_MATH_FUNC(CamelName, fname) \
case wasm::AsmTyper::StandardMember::kFFI: case wasm::AsmTyper::StandardMember::k##CamelName: { \
case wasm::AsmTyper::StandardMember::kInfinity: Handle<i::Name> name(isolate->factory()->InternalizeOneByteString( \
case wasm::AsmTyper::StandardMember::kMathAcos: STATIC_CHAR_VECTOR(#fname))); \
case wasm::AsmTyper::StandardMember::kMathAsin: Handle<i::Object> value = StdlibMathMember(isolate, stdlib, name); \
case wasm::AsmTyper::StandardMember::kMathAtan: if (value.is_null() || !value->IsJSFunction()) { \
case wasm::AsmTyper::StandardMember::kMathCos: return false; \
case wasm::AsmTyper::StandardMember::kMathSin: } \
case wasm::AsmTyper::StandardMember::kMathTan: Handle<i::JSFunction> func(i::JSFunction::cast(*value)); \
case wasm::AsmTyper::StandardMember::kMathExp: return func->shared()->code() == \
case wasm::AsmTyper::StandardMember::kMathLog: isolate->builtins()->builtin(Builtins::k##CamelName); \
case wasm::AsmTyper::StandardMember::kMathCeil: }
case wasm::AsmTyper::StandardMember::kMathFloor: STDLIB_MATH_FUNC(MathAcos, acos)
case wasm::AsmTyper::StandardMember::kMathSqrt: STDLIB_MATH_FUNC(MathAsin, asin)
case wasm::AsmTyper::StandardMember::kMathAbs: STDLIB_MATH_FUNC(MathAtan, atan)
case wasm::AsmTyper::StandardMember::kMathClz32: STDLIB_MATH_FUNC(MathCos, cos)
case wasm::AsmTyper::StandardMember::kMathMin: STDLIB_MATH_FUNC(MathSin, sin)
case wasm::AsmTyper::StandardMember::kMathMax: STDLIB_MATH_FUNC(MathTan, tan)
case wasm::AsmTyper::StandardMember::kMathAtan2: STDLIB_MATH_FUNC(MathExp, exp)
case wasm::AsmTyper::StandardMember::kMathPow: STDLIB_MATH_FUNC(MathLog, log)
case wasm::AsmTyper::StandardMember::kMathImul: STDLIB_MATH_FUNC(MathCeil, ceil)
case wasm::AsmTyper::StandardMember::kMathFround: STDLIB_MATH_FUNC(MathFloor, floor)
case wasm::AsmTyper::StandardMember::kMathE: STDLIB_MATH_FUNC(MathSqrt, sqrt)
case wasm::AsmTyper::StandardMember::kMathLN10: STDLIB_MATH_FUNC(MathAbs, abs)
case wasm::AsmTyper::StandardMember::kMathLN2: STDLIB_MATH_FUNC(MathClz32, clz32)
case wasm::AsmTyper::StandardMember::kMathLOG2E: STDLIB_MATH_FUNC(MathMin, min)
case wasm::AsmTyper::StandardMember::kMathLOG10E: STDLIB_MATH_FUNC(MathMax, max)
case wasm::AsmTyper::StandardMember::kMathPI: STDLIB_MATH_FUNC(MathAtan2, atan2)
case wasm::AsmTyper::StandardMember::kMathSQRT1_2: STDLIB_MATH_FUNC(MathPow, pow)
case wasm::AsmTyper::StandardMember::kMathSQRT2: STDLIB_MATH_FUNC(MathImul, imul)
// TODO(bradnelson) Actually check these. STDLIB_MATH_FUNC(MathFround, fround)
return true; #undef STDLIB_MATH_FUNC
#define STDLIB_MATH_CONST(cname, const_value) \
case wasm::AsmTyper::StandardMember::kMath##cname: { \
i::Handle<i::Name> name(isolate->factory()->InternalizeOneByteString( \
STATIC_CHAR_VECTOR(#cname))); \
i::Handle<i::Object> value = StdlibMathMember(isolate, stdlib, name); \
return !value.is_null() && value->IsNumber() && \
value->Number() == const_value; \
}
STDLIB_MATH_CONST(E, 2.718281828459045)
STDLIB_MATH_CONST(LN10, 2.302585092994046)
STDLIB_MATH_CONST(LN2, 0.6931471805599453)
STDLIB_MATH_CONST(LOG2E, 1.4426950408889634)
STDLIB_MATH_CONST(LOG10E, 0.4342944819032518)
STDLIB_MATH_CONST(PI, 3.141592653589793)
STDLIB_MATH_CONST(SQRT1_2, 0.7071067811865476)
STDLIB_MATH_CONST(SQRT2, 1.4142135623730951)
#undef STDLIB_MATH_CONST
default: { UNREACHABLE(); } default: { UNREACHABLE(); }
} }
return false; return false;
......
...@@ -326,6 +326,7 @@ AsmTyper::VariableInfo* AsmTyper::ImportLookup(Property* import) { ...@@ -326,6 +326,7 @@ AsmTyper::VariableInfo* AsmTyper::ImportLookup(Property* import) {
if (i == stdlib->end()) { if (i == stdlib->end()) {
return nullptr; return nullptr;
} }
stdlib_uses_.insert(i->second->standard_member());
return i->second; return i->second;
} }
...@@ -429,7 +430,6 @@ AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) { ...@@ -429,7 +430,6 @@ AsmTyper::StandardMember AsmTyper::VariableAsStandardMember(Variable* var) {
return kNone; return kNone;
} }
StandardMember member = var_info->standard_member(); StandardMember member = var_info->standard_member();
stdlib_uses_.insert(member);
return member; return member;
} }
......
...@@ -47,29 +47,91 @@ var stdlib = this; ...@@ -47,29 +47,91 @@ var stdlib = this;
})(); })();
(function TestBadNaNStdlib() { var stdlib = this;
var stdlib_root_members = [
'Infinity',
'NaN',
];
var stdlib_math_members = [
'E',
'LN10',
'LN2',
'LOG2E',
'LOG10E',
'PI',
'SQRT1_2',
'SQRT2',
'ceil',
'clz32',
'floor',
'sqrt',
'abs',
'min',
'max',
'acos',
'asin',
'atan',
'cos',
'sin',
'tan',
'exp',
'log',
'atan2',
'pow',
'imul',
'fround',
];
(function TestBadStdlib() {
function Module(stdlib) { function Module(stdlib) {
"use asm"; "use asm";
var StdlibNaN = stdlib.NaN; var foo = stdlib.NaN;
function foo() { return +StdlibNaN; }
return {}; return {};
} }
assertThrows(function() { for (var i = 0; i < stdlib_root_members.length; ++i) {
Wasm.instantiateModuleFromAsm(Module.toString(), { NaN: 0 }); var member = stdlib_root_members[i];
}); var stdlib = {};
stdlib[member] = 0;
print(member);
var code = Module.toString().replace('NaN', member);
assertThrows(function() {
Wasm.instantiateModuleFromAsm(code, stdlib);
});
}
for (var i = 0; i < stdlib_math_members.length; ++i) {
var member = stdlib_math_members[i];
var stdlib = {Math:{}};
stdlib['Math'][member] = 0;
print(member);
var code = Module.toString().replace('NaN', 'Math.' + member);
assertThrows(function() {
Wasm.instantiateModuleFromAsm(code, stdlib);
});
}
})(); })();
(function TestMissingNaNStdlib() { (function TestMissingNaNStdlib() {
function Module(stdlib) { function Module(stdlib) {
"use asm"; "use asm";
var StdlibNaN = stdlib.NaN; var foo = stdlib.NaN;
function foo() { return +StdlibNaN; }
return {}; return {};
} }
assertThrows(function() { for (var i = 0; i < stdlib_root_members.length; ++i) {
Wasm.instantiateModuleFromAsm(Module.toString(), {}); var member = stdlib_root_members[i];
}); var code = Module.toString().replace('NaN', member);
assertThrows(function() {
Wasm.instantiateModuleFromAsm(code, {});
});
}
for (var i = 0; i < stdlib_math_members.length; ++i) {
var member = stdlib_math_members[i];
var code = Module.toString().replace('NaN', 'Math.' + member);
assertThrows(function() {
Wasm.instantiateModuleFromAsm(code, {});
});
}
})(); })();
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment