Skip to content

Fix bad codegen for fixed buffer access#26351

Merged
jaredpar merged 4 commits intodotnet:dev15.7.xfrom
agocke:bug-fixed-fields
Apr 24, 2018
Merged

Fix bad codegen for fixed buffer access#26351
jaredpar merged 4 commits intodotnet:dev15.7.xfrom
agocke:bug-fixed-fields

Conversation

@agocke
Copy link
Copy Markdown
Member

@agocke agocke commented Apr 23, 2018

Customer scenario

Very common usages of fixed buffers will cause failures in Mono and potentially other runtimes due to bad IL. The IL is rejected due to type system violations, but is semantically correct. This causes the CLR to accept the IL and run it as expected. Mono is stricter, however, and other runtimes may also reject the program.

Bugs this fixes

#26335
https://devdiv.visualstudio.com/DevDiv/_workitems/edit/605434

Workarounds, if any

For Mono, there are none.

Risk

This is a change localized to fixed buffer field access in lowering.

Performance impact

None, this is a minor change in logic.

Is this a regression from a previous update?

Yes.

Root cause analysis

Unfortunately, the desktop CLR and CoreCLR both accept this IL and run it as expected. Type system violations like this are usually caught with PEVerify, but since this is unsafe code by definition, PEVerify cannot be used to find this violation.

How was the bug found?

Mono reported this bug when they upgraded their baseline compiler.

When generating a pinning temp for fixed statements on
fixed buffers, the type for the pinning temp is ref to
the type of the fixed field. However, in our lowering
the type of a fixed buffer field is a pointer type, while
what we actually want for the pinning temp is a ref to
the underlying type. This change fixes that scenario.

Fixes dotnet#26335
@agocke agocke requested a review from a team as a code owner April 23, 2018 23:16
@agocke agocke added this to the 15.7 milestone Apr 23, 2018
@agocke
Copy link
Copy Markdown
Member Author

agocke commented Apr 23, 2018

cc @jaredpar

@jaredpar
Copy link
Copy Markdown
Member

cc @dotnet/roslyn-compiler for review

@MeiChin-Tsai
Copy link
Copy Markdown

Approved but do get the PR reviewed.

Copy link
Copy Markdown
Member

@VSadov VSadov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@jaredpar
Copy link
Copy Markdown
Member

Hold off on merge until we get division approval.

fieldAccess.FieldSymbol,
fieldAccess.ConstantValueOpt,
fieldAccess.ResultKind,
initializerType);
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Apr 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

initializerType [](start = 20, length = 15)

This doesn't look right to me. The node is no longer consistent. #Closed

initializerExpr = ((BoundAddressOfOperator)initializerExpr).Operand;

TypeSymbol initializerType = initializerExpr.Type;
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Apr 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TypeSymbol initializerType = initializerExpr.Type; [](start = 12, length = 50)

It looks like before the break, we were getting the type from the BoundAddressOfOperator, before digging through it. Can we restore the same logic instead of trying to patch the type later? #Closed

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type would still be wrong. The problem is that we need to actually change the type from pointer to reference, but the language sees a fixed buffer as being of pointer type. We could change the type earlier in codegen, but I think that would be a riskier change.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree that would be riskier. If we feel it is the better change then my suggestion:

  1. Keep the fix in the more constrained form here.
  2. File a bug to fix the type up earlier in the compiler in the 15.8 release.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but I think that would be a riskier change.

Before we can make this call, we should actually understand what would be the change.


In reply to: 183831907 [](ancestors = 183831907)

Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we shouldn't mangle BoundFieldAccess node for a fixed field in the local rewriter. If necessary, we should adjust emit layer to properly emit address of a fixed field when it is a source of a ref assignment.

Lo = lo;
Hi = hi;
unsafe {
fixed (int *p = Delta) {
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Apr 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed (int *p = Delta) { [](start = 16, length = 24)

Consider adding a test for a static fixed field and for access to an instance fixed field outside of the declaring type. #Closed

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Static fixed fields are tested in FixedSizeBufferTests.StaticFixedBuffer and instance fixed fields outside the declaring type is tested in FixedSizeBufferTests.FixedStatementOnFixedBuffer.

{
public class FixedSizeBufferTests : EmitMetadataTestBase
{
[Fact]
Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs Apr 24, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Fact] [](start = 8, length = 6)

WorkItem? #Closed

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added.

@AlekseyTs
Copy link
Copy Markdown
Contributor

AlekseyTs commented Apr 24, 2018

Done with review pass (iteration 2) #Closed

agocke added 2 commits April 24, 2018 12:21
…serts to allow pointer to managed ref assignment for fixed-size buffers
@AlekseyTs AlekseyTs dismissed their stale review April 24, 2018 19:35

obsolete

Copy link
Copy Markdown
Contributor

@AlekseyTs AlekseyTs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM (iteration 4), assuming all tests will pass.

@jaredpar jaredpar merged commit c599353 into dotnet:dev15.7.x Apr 24, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants