-
Notifications
You must be signed in to change notification settings - Fork 4k
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
A possible ref safety "hole" around UnscopedRef method invoked on an expression classified as a value or readonly variable of a struct type #67435
Comments
IL:
However, the behavior is fine when
|
Here is a scenario with the same readonly method that should be blocked:
It looks like the reason why receiver is a value matters. |
Note that invoking non-readonly APIs on readonly variables causes receiver to be cloned. I think that should result in an error for UnscopedRef APIs. |
@jjonescz I see you have a PR out for this, were you still interested in working on it? |
@RikkiGibson not in near future, feel free to pick it up |
@jaredpar pointed out that ref readonly int M(in int x) => ref x;
ref int ri1 = M(42);
ref int ri2 = M(43); // can't reuse temp created for '42'.
Console.Write(ri1); I'm trying to determine if we should preserve compat and try to avoid reuse of temps here, or if we can/should just make the call an error. Maybe we should have a wider discussion about it. |
FWIW, we had a small discussion and iirc Aleksey suggested to make this an error first and only if that's a problem, try to fix how the temps are reused: #67955 (comment) |
@AlekseyTs @jaredpar and I discussed this issue today. Conclusions:
|
For visibility, here's a simple repro from #73438: using System;
ReadOnlySpan<bool> a = new(true);
ReadOnlySpan<bool> b = new(false);
Console.WriteLine(a[0]); // should print True; prints False
Console.WriteLine(b[0]); // prints False; that's ok |
Compile and run the following code:
https://sharplab.io/#v2:EYLgtghglgdgNAFxAJwK4wD4GIaoDZ4TB4CmABACZQDORpAsAFBMuMACATGQMJMDeTMkLJsAjADYyAZTIBZUQAoAlGQC8APjIwSAd2nKyfMgDE1ZURbIBfANythIiWVgI5HBchIAzZzFcAPOGkyAE8lQWEBRgcHNgB2Mn87aOEre2ExSRc5AGZlCKEomIyE2XdPH3llADoAJW9lIIpvCHwEJWSHNOYUoUzfV1kAFnzewwKY+LcPbzlFJTqGpSDtPSkDI1NVcw4c6w6J7on+7NkAVlGHIuKyADcIZESzVf0VTbNRDiHrTpupspmlXmiy8jUSBzG3QcxycbG+smgMEukQmsVE1TEAE4FLI8koITdHBjRNjhsoCX90VicRd8b8hN0jj02HtqAg0ABjVxSfjHPbZYzJCYAbTE1QAIlAIABzGAAezZUA51Gq3DlzQAgjAIHgQtQaNUAKowagcuUABxIFHqXgAunyyBUBmQbcjCqiSo7ZoLDkxukA=
Observed:
Expected either an error for
Ref
invocations, or the following output:The problem is the fact, that
Ref
is invoked on a value (vs. a variable) and its result refers to a memory in a short lived temp synthesized by compiler. The lifetime of that temp is theRef
invocation. Compiler is free to reuse it afterwards. Effectively, we end up with a reference to a memory that is no longer alive. This can be observed in IL forM3
:Note that local 0 is used with different values in the process of calculating both arguments for
M2
.Perhaps compiler should disallow invoking UnscopedRef methods on expressions classified as values of struct types. It should be fine to invoke such methods on expressions classified as variables of struct types.
The text was updated successfully, but these errors were encountered: