Closed Bug 1952171 Opened 15 days ago Closed 14 days ago

A bug in JIT optimization: an exception about outputs changed of String()

Categories

(Core :: JavaScript Engine: JIT, defect)

Other Branch
defect

Tracking

()

RESOLVED INVALID

People

(Reporter: anbu1024.me, Unassigned)

Details

User Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/133.0.0.0 Safari/537.36 Edg/133.0.0.0

Steps to reproduce:

A bug in JIT optimization, whether there are security risks or not requires further in-depth analysis.

Version:
commit 7b3f3fb5fd2cad8f348131498a35a91bef68b47b

Build options:

/bin/sh ../../gecko-dev/js/src/configure --enable-debug --disable-optimize --disable-shared-js --disable-tests --enable-gczeal

Test options:

./js --baseline-warmup-threshold=10 --ion-warmup-threshold=50 --ion-check-range-analysis --ion-extra-checks --differential-testing

Case1:

Problem Description: Execution results exhibit discrepancies.

function opt() {
  const v0 = [];
  const v1 = v0.keys();
  const v2 = v1.__proto__;
  function v3() { }
  const v4 = v3.MAX_VALUE;
  const v5 = Object.bind(v4, "string");
  const v6 = { "apply": Object };
  const v7 = new Proxy(v5, v6);
  const v8 = new Proxy(Proxy, v7);
  const v9 = { "apply": v4, "call": eval, "__proto__": eval, "defineProperty": eval, "get": v8 };
  const v10 = new Proxy(v3, v9);
  const v11 = [].keys();
  const v12 = v11.__proto__;
  v12.__proto__ = v10;
  const v13 = v2.__proto__;
  const v14 = String(v13);
  return v14;
}
  
let a = opt();
let b = opt();
for (let i = 0; i < 55; i++) {
  opt();
}
let c = opt();
print(JSON.stringify(a));
print(JSON.stringify(b));
print(JSON.stringify(c));

Case2:

Problem Description: Execution results exhibit discrepancies.

function opt() {
  function v0() { }
  const v1 = String.bind();
  const v2 = { "apply": Object };
  const v3 = new Proxy(v1, v2);
  const v4 = new Proxy(Proxy, v3);
  const v5 = { "apply": eval, "call": eval, "__proto__": eval, "defineProperty": eval, "get": v4 };
  const v6 = new Proxy(v0, v5);
  const v7 = [].keys();
  const v8 = v7.__proto__;
  v8.__proto__ = v6;
  const v9 = String(v8);
  return v9;
}
  
let a = opt();
let b = opt();
for (let i = 0; i < 55; i++) {
  opt();
}
let c = opt();
print(JSON.stringify(a));
print(JSON.stringify(b));
print(JSON.stringify(c));

Case3:

Problem Description: Execution results exhibit discrepancies.

function opt() {
  const v0 = [].keys();
  const v1 = v0.__proto__;
  function v2() { }
  const v3 = v2.valueOf;
  const v4 = Object.bind(v3, "length");
  const v5 = { "apply": Object };
  const v6 = new Proxy(v4, v5);
  const v7 = new Proxy(Proxy, v6);
  const v8 = { "apply": eval, "call": eval, "__proto__": eval, "defineProperty": eval, "get": v7 };
  const v11 = new Proxy(v2, v8);
  const v12 = [].keys();
  const v13 = v12.__proto__;
  v13.__proto__ = v11;
  const v14 = v1.__proto__;
  const v15 = String(v14);
  return v15;
}
  
let a = opt();
let b = opt();
for (let i = 0; i < 55; i++) {
  opt();
}
let c = opt();
print(JSON.stringify(a));
print(JSON.stringify(b));
print(JSON.stringify(c));

Case4:

Problem Description: Execution results exhibit discrepancies.

function opt() {
  const v0 = [].keys();
  const v1 = v0.__proto__;
  function v2() { }
  const v3 = String.bind();
  const v4 = { "apply": Object };
  const v5 = new Proxy(v3, v4);
  const v6 = new Proxy(Object, v5);
  const v7 = { "apply": eval, "call": eval, "__proto__": eval, "defineProperty": eval, "get": v6 };
  const v8 = new Proxy(v2, v7);
  const v9 = [].keys();
  const v10 = v9.__proto__;
  v10.__proto__ = v8;
  const v11 = String(v1);
  return v11;
}
  
let a = opt();
let b = opt();
for (let i = 0; i < 55; i++) {
  opt();
}
let c = opt();
print(JSON.stringify(a));
print(JSON.stringify(b));
print(JSON.stringify(c));

Actual results:

The result has changed after JIT optimization.

Case1:

a = "function() {\n    [native code]\n}"
b = "function() {\n    [native code]\n}"
c = ""

Case2:

a = "string"
b = "string"
c = "function Proxy() {\n    [native code]\n}"

Case3:

a = "function() {\n    [native code]\n}"
b = "function() {\n    [native code]\n}"
c = ""

Case4:

a = "string"
b = "string"
c = "function Object() {\n    [native code]\n}"
Group: core-security → javascript-core-security

Thanks for the report, but this is working as expected. By mutating prototypes, calling opt has side-effects that cause future calls to return different results.

Other JS engines agree that this is the correct behaviour (although we all differ on exactly how we print functions).

Group: javascript-core-security
Status: NEW → RESOLVED
Closed: 14 days ago
Resolution: --- → INVALID
You need to log in before you can comment on or make changes to this bug.