-
Notifications
You must be signed in to change notification settings - Fork 4.8k
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
P/Invoke and GCHandle pinning regression on .NET 5.0.301 #55944
Comments
Tagging subscribers to this area: @dotnet/area-system-io-compression Issue DetailsDescriptionSummaryUpdating .NET runtime to 5.0.301 from 5.0.202 broke the existing p/invoke code. I have written a zlib pinvoke library, Joveler.Compression.Zlib. I highly suspect a bug of .NET runtime in handling pinned GCHandle. Detailszlib uses C struct Thus the wrapper must pin // This code worked prior to .NET SDK 5.0.301
_zs64 = new ZStreamL64(); // .NET translated z_stream
_zsPin = GCHandle.Alloc(_zs64, GCHandleType.Pinned); // GCHandle pinning
...
ZLibRet ret = ZLibInit.Lib.L32.Deflate(_zs32, ZLibFlush.NoFlush); // returns Z_STREAM_ERROR on .NET SDK 5.0.301 If I change the code not to pin GCHandle, its test code randomly fails on every .NET platform. // This code randomly fails on .NET Framework 4.8, .NET Core 3.1, .NET 5.0
_zs64 = new ZStreamL64(); // .NET translated z_stream
_zsPin = GCHandle.Alloc(_zs64, GCHandleType.Pinned); // Does not pins GCHandle
...
ZLibRet ret = ZLibInit.Lib.L32.Deflate(_zs32, ZLibFlush.NoFlush); // randomly returns Z_STREAM_ERROR Thus I think there is a high possibility on .NET SDK 5.0.301 or higher has a bug with handling pinned GCHandle. Configuration
Regression?The test code worked on every .NET platform prior to 5,0.203.
Other informationReproduceTo reproduce this issue, simply checkout Joveler.Compression repo and run the tests on .NET SDK 5.0.301 or higher. To test GCHandle pinning effect, change L182 and L173 of // BEFORE (pinned)
_zsPin = GCHandle.Alloc(<HANDLE>, GCHandleType.Pinned);
// AFTER (not pinned)
_zsPin = GCHandle.Alloc(<HANDLE>, GCHandleType.Normal); Why suspect GCHandle pinning?Different from my zlib wrapper, my xz-utils wrapper and lz4 wrapper works fine on the latest .NET SDK. The only thing zlib wrapper does differently is the GCHandle pinning of Credit to @Luzifix who noticed and reported test failure.
|
Please tag @dotnet/area-GC-coreclr, as it is likely to be an issue with GC. |
Tagging subscribers to this area: @dotnet/gc Issue DetailsDescriptionSummaryUpdating .NET runtime to 5.0.301 from 5.0.202 breaks the existing p/invoke code. I have a zlib pinvoke library, Joveler.Compression.Zlib. I highly suspect a bug of .NET runtime in handling pinned GCHandle. Detailszlib uses C struct Thus the wrapper must pin // This code worked prior to .NET SDK 5.0.301
_zs64 = new ZStreamL64(); // .NET translated z_stream
_zsPin = GCHandle.Alloc(_zs64, GCHandleType.Pinned); // GCHandle pinning
...
ZLibRet ret = ZLibInit.Lib.L32.Deflate(_zs64, ZLibFlush.NoFlush); // returns Z_STREAM_ERROR on .NET SDK 5.0.301 If I change the code not to pin GCHandle, its test code randomly fails on every .NET platform. // This code randomly fails on .NET Framework 4.8, .NET Core 3.1, .NET 5.0
_zs64 = new ZStreamL64(); // .NET translated z_stream
_zsPin = GCHandle.Alloc(_zs64, GCHandleType.Pinned); // Does not pins GCHandle
...
ZLibRet ret = ZLibInit.Lib.L32.Deflate(_zs64, ZLibFlush.NoFlush); // randomly returns Z_STREAM_ERROR Therefore, it is highly suspected that there is a bug around pinned GCHandle handling since .NET SDK 5.0.301. Configuration
Regression?The test code worked on every .NET platform prior to 5,0.301.
Other informationReproduceTo reproduce this issue, simply checkout Joveler.Compression repo and run the tests on .NET SDK 5.0.301 or higher. To test GCHandle pinning effect, change L182 and L173 of // BEFORE (pinned)
_zsPin = GCHandle.Alloc(<HANDLE>, GCHandleType.Pinned);
// AFTER (not pinned)
_zsPin = GCHandle.Alloc(<HANDLE>, GCHandleType.Normal); Why suspect GCHandle pinning?Different from my zlib wrapper, my xz-utils wrapper and lz4 wrapper works fine on the latest .NET SDK. The only thing zlib wrapper does differently is the GCHandle pinning of Credit to @Luzifix who noticed and reported test failure.
|
@jkoritzinsky Fixed by #54244 ? |
Yes |
Description
Summary
Updating .NET runtime to 5.0.301 from 5.0.202 breaks the existing p/invoke code.
I have a zlib pinvoke library, Joveler.Compression.Zlib.
Its zlib inflate/deflate streaming API has broken since upgrading .NET SDK to 5.0.301.
I highly suspect a bug of .NET runtime in handling pinned GCHandle.
Details
zlib uses C struct
z_stream
as its context object, and requires the address ofz_stream
must not change while the object is alive. This is undocumented, but apparent on zlib'ss->strm != strm
check code. (s->strm
is the zlib allocated address, andstrm
is parameter address).Thus the wrapper must pin
z_stream
with GCHandle to prevent GC from moving the object.If it doesn't, zlib
deflate()/inflate()
occasionally returnsZ_STREAM_ERROR
code, as GC changed the address ofz_stream
.If I change the code not to pin GCHandle, its test code randomly fails on every .NET platform.
Therefore, it is highly suspected that there is a bug around pinned GCHandle handling since .NET SDK 5.0.301.
Configuration
Regression?
The test code worked on every .NET platform prior to 5,0.301.
You can look at Azure Pipelines build log, which was performed on 2021-04-11 with .NET 5.0.202 SDK.
Other information
Reproduce
To reproduce this issue, simply checkout Joveler.Compression repo and run the tests on .NET SDK 5.0.301 or higher.
The tests should fail like this:
To test GCHandle pinning effect, change L182 and L173 of
ZLibStreams.cs
like this:Why suspect GCHandle pinning?
Different from my zlib wrapper, my xz-utils wrapper and lz4 wrapper works fine on the latest .NET SDK. The only thing zlib wrapper does differently is the GCHandle pinning of
context object (z_stream)
.Credit to @Luzifix who noticed and reported test failure.
The text was updated successfully, but these errors were encountered: