Skip to content

Conversation

@MichalStrehovsky
Copy link
Member

This parameter is actually used as out. Per https://docs.microsoft.com/en-us/dotnet/framework/interop/blittable-and-non-blittable-types these parameters must be marked as such ("you must apply the InAttribute and OutAttribute attributes if you want to marshal the argument as an In/Out parameter"). The code currently works, because it's taking advantage of the pinning optimization that the CLR does, otherwise it would be treated as "in" only. It will keep working the same with the extra metadata, but the metadata will be correct.

Hit this while running on a runtime that doesn't do the pinning optimization (and this annotation is a fix for that).

This parameter is actually used as in/out. Per https://docs.microsoft.com/en-us/dotnet/framework/interop/blittable-and-non-blittable-types they must be marked as such ("you must apply the InAttribute and OutAttribute attributes if you want to marshal the argument as an In/Out parameter"). The code currently works, because it's taking advantage of the pinning optimization. It will keep working the same, but the metadata will be correct after the change.
@MichalStrehovsky MichalStrehovsky requested a review from a team as a code owner June 30, 2019 12:58
@RussKie RussKie requested a review from JeremyKuhne June 30, 2019 23:34
@RussKie
Copy link
Contributor

RussKie commented Jun 30, 2019

@JeremyKuhne could you please have a look?

Copy link
Member

@JeremyKuhne JeremyKuhne left a comment

Choose a reason for hiding this comment

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

It would be better to do the full fix by changing USEROBJECTFLAGS to a struct and pass it by ref.

@MichalStrehovsky
Copy link
Member Author

It would be better to do the full fix by changing USEROBJECTFLAGS to a struct and pass it by ref.

Yep, looks better. I also fixed up the Sizeof so that we don't box the new struct just to get its marshalling size.

Copy link
Member

@JeremyKuhne JeremyKuhne left a comment

Choose a reason for hiding this comment

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

Thanks! We should remove the Marshal.Sizeof as well. :)

NativeMethods.USEROBJECTFLAGS flags = new NativeMethods.USEROBJECTFLAGS();

if (UnsafeNativeMethods.GetUserObjectInformation(new HandleRef(null, hwinsta), NativeMethods.UOI_FLAGS, flags, Marshal.SizeOf(flags), ref lengthNeeded))
if (UnsafeNativeMethods.GetUserObjectInformation(new HandleRef(null, hwinsta), NativeMethods.UOI_FLAGS, ref flags, Marshal.SizeOf<NativeMethods.USEROBJECTFLAGS>(), ref lengthNeeded))
Copy link
Member

Choose a reason for hiding this comment

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

Can you turn this to sizeof(USEROBJECTFLAGS)? There's no need to hit the marshaller if it's blittable.

Copy link
Member Author

Choose a reason for hiding this comment

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

Sure, done. But it requires making the method unsafe because of dumb C# rules.

Copy link
Member

Choose a reason for hiding this comment

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

method unsafe because of dumb C# rules.

Yeah, that's one I hope to get fixed eventually. :)

}
}

[StructLayout(LayoutKind.Sequential)]
Copy link
Member

Choose a reason for hiding this comment

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

nit: the [StructLayout] isn't needed anymore

Copy link
Member Author

Choose a reason for hiding this comment

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

I tend to not touch these, because this attribute has a side effect of shutting up compiler warnings about unused fields. We'll see what the CI says (I didn't try to build any of this locally because these are all de minimis changes).

Copy link
Contributor

Choose a reason for hiding this comment

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

@JeremyKuhne Interesting, I was under the assumption that structs passed through the interop layer always needed this. Is it documented somewhere when it can be left off?

Copy link
Member Author

Choose a reason for hiding this comment

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

It's documented somewhere in the C# language spec. The C# compiler marks all structures as sequential by default.

Copy link
Member

Choose a reason for hiding this comment

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

I was under the assumption that structs passed through the interop layer always needed this.

StructLayoutAttribute is a pseudo attribute (see ECMA 335: I I.21.2.1) which means what you're typing in code isn't actually stored as a normal attribute. The IL flag it relates to is always set one way or another, which you can see in IL with the auto, sequential, and explicit keywords on the type. When reflecting the attribute is always manually created for you if you try and look for it.

Our general interop guidelines are to not add attributes that are default behavior, which is what I'm calling out here. As @MichalStrehovsky calls out, in this particular case C# might complain about unused fields without it being explicitly put in code. I think the rule for that one is constrained to public types, and it might have an out for things in "NativeMethods" classes, I'm not entirely sure. You also have to have this explicitly defined if you have char fields so you can specify that they're Unicode rather than ANSI (the default) for marshalling (i.e. [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)])

Copy link
Contributor

Choose a reason for hiding this comment

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

Yeah I knew about all that but I was thinking the default was auto not sequential, interesting that it isn't.

@RussKie RussKie merged commit 3b79118 into dotnet:master Jul 1, 2019
@MichalStrehovsky MichalStrehovsky deleted the patch-1 branch July 2, 2019 05:49
MichalStrehovsky added a commit to MichalStrehovsky/corefx that referenced this pull request Jul 8, 2019
jkotas pushed a commit to dotnet/corefx that referenced this pull request Jul 8, 2019
@ghost ghost locked as resolved and limited conversation to collaborators Feb 5, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants