-
Notifications
You must be signed in to change notification settings - Fork 305
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implements compilation of the delete operator #461
base: main
Are you sure you want to change the base?
Implements compilation of the delete operator #461
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Overall looks good already, with a few suggestions
|
||
if case .memberExpression(let memberExpression) = argumentExpression { | ||
let obj = try compileExpression(memberExpression.object) | ||
let isGuarded = memberExpression.isOptional |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this could use a comment. I guess you are effectively turning
delete a?.b;
into
try { delete a.b; } catch {}
?
I think that makes sense, but a short comment might be nice :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here is an example of before and after:
Before
const nestedObj = { a: { b: 2 } };
delete nestedObj.a?.c;
After
const o1 = {
"b": 2,
};
const o2 = {
"a": o1,
};
o2.a?.c;
const t6 = o2.a;
delete t6?.c;
So, no try catch enveloping which is nice in my opinion :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! Though were does the o2.a?.c;
line come from? Is that maybe a bug in our lifting, or is that property access also there in the IL?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, good catch! This happened because
let argument = try compileExpression(unaryExpression.argument)
was called, even though argument
was not used in the delete case. This is fixed now. I will be looking more carefully at the FuzzIL translation in the future!
Regarding you comments:
|
Regarding 1), I initially had this in the code, but then I found out that an implicit global variable does not become a property of I did a quick check of how many files in test/mjsunit/* have |
console.log(arr); | ||
|
||
const nestedObj = { a: { b: 2 } }; | ||
console.log(delete nestedObj?.a?.b); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe also add a test for something like
try {
delete null.a;
} catch(e) {
console.log(e.message);
}
console.log(delete null?.a);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is compilable. However, this would cause DeleteProperty to be called, even though null is not an object. In Compiler.swift, I believe it is currently not possible to check here if obj is truly an object. We could either
- Try preventing this in parser.js, although there are possibly more edge cases than just this
- Ignore it and add a TODO
- Introduce a new DeleteAny JSOperation
What would you prefer?
|
||
if case .memberExpression(let memberExpression) = argumentExpression { | ||
let obj = try compileExpression(memberExpression.object) | ||
let isGuarded = memberExpression.isOptional |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good! Though were does the o2.a?.c;
line come from? Is that maybe a bug in our lifting, or is that property access also there in the IL?
Cool, just a question and one more suggestion. And sounds good, let's not bother with |
This branches enables compilation of the delete operator. Some thoughts I think are worth mentioning
1)
With this change, approximately 300 new seeds from test/mjsunit and the SpiderMonkey JIT test files will become compilable. If Fuzzilli treats the delete operation as a standard unary operator, delete might be applied to non-object properties, such as simple variables (var). If I understand correctly, semantic correctness will not be significantly impacted because delete does not cause a crash when called on unintended targets. For example, if applied to var, let, or parameters, it simply returns false and has no effect.
2)
It can happen that an object has a key that is a number. In that case DeleteElement will be called, even though it is not an array.
Example:
Similarly, we can delete elements from an array based on a computed index - in that case DeleteComputedProperty is called, not DeleteElement.
Example
Is that a problem? IIUC, the main difference between DeleteElement and Delete(Computed)Property In FuzzIL is only syntactical, not semantical.