-
-
Notifications
You must be signed in to change notification settings - Fork 672
opti: avoid set shadowstack for (call local.get) pattern #2731
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
Conversation
Co-authored-by: Max Graey <maxgraey@gmail.com>
Co-authored-by: Max Graey <maxgraey@gmail.com>
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.
Apart from the comment below, I wonder if there is unsafe code in stdlib that assumes call operands to go to the stack. For instance
let foo = changetype<usize>(new Foo());
...
someFunc(changetype<Foo>(foo));
would be such a pattern, where the local foo
is not placed on the shadow stack due to being typed as usize
, and with the change the call wouldn't place the value on the shadow stack either, then risking that the value is collected too early. Not sure if this is actually done, but I guess we should reasonably check that this pattern isn't used?
@@ -170,10 +170,27 @@ function matchPattern(module: Module, expr: ExpressionRef): ExpressionRef { | |||
} | |||
|
|||
/** Tests whether a `value` matched by `matchTostack` needs a slot. */ | |||
function needsSlot(module: Module, value: ExpressionRef): bool { | |||
function needsSlotInCall(module: Module, value: ExpressionRef): bool { |
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.
Instead of duplicating the function, needsSlot
could take a third argument isCallOperand: bool = false
perhaps, then returning !isCallOperand
on local gets. Wdyt?
I don't find this pattern is std. And I think it will be danger only in this scenario: class A {}
function f3(a: A): void {
__unpin(changetype<usize>(a))
// there 'a' is unsafe
}
export function f2callback(v: usize): void {
f3(changetype<A>(v));
}
declare function f2(v: usize): void; // setTimeout(()=> f2callback, 100)
export function f1(): void {
let a = new A();
__pin(changetype<usize>(a));
f2(changetype<usize>(a));
} Wdyt? Maybe this optimization is not work. |
optimize shadowstack
For (call local.get) pattern, local variable won't be changed in called function. So it is not needed to store the value of local.get in shadowstack