Skip to content

Commit

Permalink
always expose safe functions from HermesInternal
Browse files Browse the repository at this point in the history
Summary:
This diff changes the behavior of enableHermesInternal=false from hiding all
functions to hiding only the unsafe functions.

`HermesInternal.concat` is an example of safe function that template literal
relied on and exposing it fix the bug that using template literal throw
TypeError under runtime config `enableHermesInternal=false`.

Reviewed By: tmikov

Differential Revision: D23638791

fbshipit-source-id: 10d75dee1eb499d389024fba8ac76e6c6ff9a55e
  • Loading branch information
Huxpro authored and facebook-github-bot committed Sep 11, 2020
1 parent 61dd028 commit 36a1980
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 29 deletions.
58 changes: 31 additions & 27 deletions lib/VM/JSLib/HermesInternal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -676,17 +676,44 @@ Handle<JSObject> createHermesInternalObject(
Runtime *runtime,
const JSLibFlags &flags) {
Handle<JSObject> intern = runtime->makeHandle(JSObject::create(runtime));
if (!flags.enableHermesInternal) {
JSObject::preventExtensions(*intern);
return intern;
}

DefinePropertyFlags constantDPF =
DefinePropertyFlags::getDefaultNewPropertyFlags();
constantDPF.enumerable = 0;
constantDPF.writable = 0;
constantDPF.configurable = 0;

// Make a copy of the original String.prototype.concat implementation that we
// can use internally.
// TODO: we can't make HermesInternal.concat a static builtin method now
// because this method should be called with a meaningful `this`, but
// CallBuiltin instruction does not support it.
auto propRes = JSObject::getNamed_RJS(
runtime->makeHandle<JSObject>(runtime->stringPrototype),
runtime,
Predefined::getSymbolID(Predefined::concat));
assert(
propRes != ExecutionStatus::EXCEPTION && !(*propRes)->isUndefined() &&
"Failed to get String.prototype.concat.");
auto putRes = JSObject::defineOwnProperty(
intern,
runtime,
Predefined::getSymbolID(Predefined::concat),
constantDPF,
runtime->makeHandle(std::move(*propRes)));
assert(
putRes != ExecutionStatus::EXCEPTION && *putRes &&
"Failed to set HermesInternal.concat.");
(void)putRes;

// If `enableHermesInternal=false`, hide functions that aren't considered
// safe. All functions that are known to be safe should be defined above this
// check.
if (!flags.enableHermesInternal) {
JSObject::preventExtensions(*intern);
return intern;
}

auto defineInternMethod =
[&](Predefined::Str symID, NativeFunctionPtr func, uint8_t count = 0) {
(void)defineMethod(
Expand Down Expand Up @@ -740,29 +767,6 @@ Handle<JSObject> createHermesInternalObject(
defineInternMethodAndSymbol("getCallStack", hermesInternalGetCallStack, 0);
#endif // HERMESVM_EXCEPTION_ON_OOM

// Make a copy of the original String.prototype.concat implementation that we
// can use internally.
// TODO: we can't make HermesInternal.concat a static builtin method now
// because this method should be called with a meaningful `this`, but
// CallBuiltin instruction does not support it.
auto propRes = JSObject::getNamed_RJS(
runtime->makeHandle<JSObject>(runtime->stringPrototype),
runtime,
Predefined::getSymbolID(Predefined::concat));
assert(
propRes != ExecutionStatus::EXCEPTION && !(*propRes)->isUndefined() &&
"Failed to get String.prototype.concat.");
auto putRes = JSObject::defineOwnProperty(
intern,
runtime,
Predefined::getSymbolID(Predefined::concat),
constantDPF,
runtime->makeHandle(std::move(*propRes)));
assert(
putRes != ExecutionStatus::EXCEPTION && *putRes &&
"Failed to set HermesInternal.concat.");
(void)putRes;

JSObject::preventExtensions(*intern);

return intern;
Expand Down
19 changes: 17 additions & 2 deletions test/hermes/internal-test-methods.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@
// RUN: %hermes -Xhermes-internal-test-methods=true %s | %FileCheck --match-full-lines --check-prefix=CHKIME %s
// RUN: %hermes -Xhermes-internal-test-methods=false %s | %FileCheck --match-full-lines --check-prefix=CHKIMD %s

// Check that we can disable all fields of HermesInternal.
print(Object.getOwnPropertyNames(HermesInternal).length !== 0);
// HermesInternal.concat
var SAFE_FIELDS_COUNT = 1;

// Check that we can disable unsafe fields of HermesInternal.
print(Object.getOwnPropertyNames(HermesInternal).length !== SAFE_FIELDS_COUNT);
//CHKHIE: true
//CHKHID: false
//CHKIME: true
Expand All @@ -23,3 +26,15 @@ print(typeof HermesInternal.detachArrayBuffer);
//CHKHID-NEXT: undefined
//CHKIME-NEXT: function
//CHKIMD-NEXT: undefined

// Check that HermesInternal.concat is kept even HermesInternal is diabled.
print(typeof HermesInternal.concat)
//CHKHIE-NEXT: function
//CHKHID-NEXT: function
//CHKIME-NEXT: function
//CHKIMD-NEXT: function
print(`hello${1 + 1}world`);
//CHKHIE-NEXT: hello2world
//CHKHID-NEXT: hello2world
//CHKIME-NEXT: hello2world
//CHKIMD-NEXT: hello2world

0 comments on commit 36a1980

Please sign in to comment.