Skip to content

Data flow incorrectly handles out and ref parameters #101734

@vitek-karas

Description

@vitek-karas

Out parameters should behave like return values in a way - they get assigned a value from within the method body (this works), and they are "read" by the caller (this doesn't work). For example:

TryGetAnnotatedValue (out typeWithMethods);
typeWithMethods.RequiresPublicFields (); // Should IL2067 - mismatch of annotations

static bool TryGetAnnotatedValue([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicMethods)] out Type typeWithMethods)

The local variable (or stack slot) is not assigned a value after the call to the method with out parameter.

This also means that this doesn't warn:

Type typeWithMethods = null;
TryGetAnnotatedValue (out typeWithMethods);
typeWithMethods.RequiresPublicFields ();

That's correct, but for a wrong reason - the typeWithMethods is tracked throughout the method with a null literal value, nothing else.

But this will warn, twice:

Type typeWithMethods;
TryGetAnnotatedValue (out typeWithMethods); // IL2062 - the `typeWithMethods` doesn't have a value -> unknown value  we check it against the declared parameter
typeWithMethods.RequiresPublicFields (); // IL2062 - the out call above didn't assign value, so it's still "unknown"

This should not warn at all.

There probably other cases where this is broken. What I can see as two issues:

  • The "input" value for a out parameter should only be checked if it's a parameter/field, so to simplify only if it's a value with annotation. Known (literal, string, type) or unknown values should not check anything and should be accepted as those will be overwritten.
  • After the call with an out parameter, the value passed in should be "assigned" the value of the out parameter - so from that point on, it should be tracked as an annotated value (pointing to the out parameter as its source), regardless of what the value was before the call.

The second problem applies to ref parameters as well - the value of the variable/stackslot after a call with ref parameter should be an annotated value (pointing to the ref parameter), since the ref parameter acts like an out parameter after the call. On the other hand before the call, the value must be checked as normal in parameter.

Metadata

Metadata

Assignees

Labels

area-Tools-ILLink.NET linker development as well as trimming analyzers

Type

No type

Projects

Status

No status

Relationships

None yet

Development

No branches or pull requests

Issue actions