Compiler warning for lock when the target type is string #10282
Unanswered
alfattah-id
asked this question in
Language Ideas
Replies: 1 comment 4 replies
|
This is not something that is suitable at the compiler level. Locking on a string is fine, if you know the ownership of your string, and it is safe. For things like literals, that is likely not what you want (however, that is not something the compiler knows/tracks). You could write an analyzer for this. Regardless, this isn't something the language has a say in. (it could say this is not allowed. but we would not do that as that would definitely be a breaking change for people doing this intentionally). |
4 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
Compiler warning for
lockwhen the target type isstringSummary
I recently found a behavior that is valid according to the current C#
locksemantics, but is very easy to misunderstand and can silently reduce concurrency.C# currently allows this without any compiler warning:
Because string literals may be interned, two unrelated object instances can reference the same string object and therefore use the same monitor.
The code remains thread-safe, but work that should be independent can unexpectedly become serialized.
I propose that the C# compiler produce a warning whenever the compile-time type of a
lockexpression isstring.Reproduction
Consider this class:
Test it using two separate instances:
A developer may reasonably expect operations on
aandbto run concurrently because:aandbare different instances_valueLockis an instance field_valueLockis private_valueLockis readonly_valueLockis not staticHowever, both
_valueLockfields may reference the same interned empty-string object.Conceptually:
As a result, both instances lock the same monitor and otherwise independent operations become serialized.
Changing the field to this restores the expected per-instance concurrency:
Why this is misleading
The syntax:
can easily be interpreted as protecting the field or variable named
_valueLock.The actual semantics are based on the identity of the object returned by the expression.
Conceptually, the code behaves like this:
The monitor belongs to the referenced object.
It does not belong to:
This distinction is especially easy to miss when the field is private, readonly, non-static, and declared separately in each object instance.
Scope
This behavior applies to both legacy and modern runtimes, including:
The issue is based on C# monitor semantics and string interning, not on a specific runtime version.
For that reason, the diagnostic should be implemented at the compiler or language-analysis level.
Related work
The risks of locking on strings are already known.
Related mechanisms include:
System.Threading.Lock, available on modern .NET targetsHowever, these mechanisms do not fully solve the discoverability problem:
System.Threading.Lockis not available on .NET Frameworklock(string)code can still compile silentlyThis proposal is specifically about compiler-level visibility when the compile-time type of a
lockexpression isstring.Proposal
The compiler should issue a warning whenever the compile-time type of a
locktarget isstring.Example:
Suggested diagnostic:
Recommended replacement:
For modern targets, another valid option is:
The warning should apply regardless of whether the string comes from:
The important condition is that the compile-time type of the lock target is
string.Why a compiler warning is appropriate
The compiler already knows the compile-time type of the lock expression.
No complex flow analysis is required to detect this case.
For example:
Even if the compiler cannot determine whether a particular string is currently interned, dynamically created, or shared elsewhere,
stringis still an unsafe synchronization target because its identity may be shared or explicitly interned.A compiler warning would make the risk visible without depending entirely on optional analyzer configuration.
Compatibility
This proposal does not require changing:
Monitor.EnterMonitor.ExitThe diagnostic could initially be introduced as a warning to preserve source compatibility.
Projects that intentionally lock on a string could suppress the warning explicitly.
The warning should also support normal
.editorconfigseverity configuration, for example:or:
Optional strict lock analysis
If enabling the warning by default is considered too disruptive, an optional strict lock-analysis mode could be introduced, similar to nullable reference analysis.
For example:
A strict mode could later detect additional unsafe lock targets such as:
However, the primary proposal is intentionally limited to
string, because that case is direct, unambiguous, and easy for the compiler to identify.Documentation improvement
The documentation for
lockshould prominently explain that:locks the monitor associated with the object reference produced by
expression.It does not lock the variable or field represented by that expression.
Conceptually, the current behavior is closer to:
than:
No syntax change is required, but this distinction should be clearer in both documentation and diagnostics.
Expected outcome
The following code should not compile silently when modern safety diagnostics are enabled:
The compiler should guide the developer toward:
This would help prevent:
The change would improve synchronization safety for both .NET Framework and modern .NET without changing runtime behavior.
All reactions