question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

`Iot.Device.Common.ValueArray<T>` is not safe and contains GC holes

See original GitHub issue

Describe the bug I want to preface this by stating that I’m not a consumer of these APIs, I just happened to come across this while perusing source.dot.net.

The ValueArray<T> type introduced in https://github.com/dotnet/iot/pull/1701 stores a sequence of 8 elements, and allows consumers to retrieve a Span<T> wrapping them. However, the method for which it does this is not safe and causes the GC to lose track of the references, meaning that the object they belong to may be eligible for garbage collection while the Span<T> is in use.

For reference, this is the current implementation of ValueArray<T>.AsSpan:

public unsafe Span<T> AsSpan()
{
    return new Span<T>(Unsafe.AsPointer(ref _e0), _count);
}

And this would be an implementation that retains GC tracking (compatible with .NET Core/Standard 2.1 and newer):

public Span<T> AsSpan()
{
    return MemoryMarshal.CreateSpan(ref _e0, _count);
}

Unfortunately, MemoryMarshal.CreateSpan is not available on .NET Standard 2.0. A close equivalent to this API used to exist that would have made it possible to create Span<T> instances for ValueArray<T>s stored within classes safely (see https://github.com/dotnet/runtime/issues/27690 and https://github.com/dotnet/runtime/issues/24562).

As the ValueArray<T> type is stored within classes, changing it to a ref struct is also not an option, meaning that there is no safe way to implement AsSpan on ValueArray<T> under .NET Standard 2.0.

Issue Analytics

  • State:closed
  • Created a year ago
  • Reactions:5
  • Comments:17 (9 by maintainers)

github_iconTop GitHub Comments

2reactions
DaZombieKillercommented, Jul 14, 2022

BTW C# does not allow unmanaged types to be used when the struct constraint is applied.

An unmanaged type is merely a struct that doesn’t contain any GC pointers. I assume you meant that it does not allow managed types? This is also not true though, as while it disallows using a class directly for T, you can still use a struct that contains a class as one of its fields.

So, as a result, ValueArray<T> can indirectly contain a GC pointer if T does, because it is constrained to struct and not unmanaged. Either way though, the GC issues still apply.

1reaction
PJB3005commented, Jul 14, 2022

To be clear here: there are two separate issues at play.

On .NET Framework, Span uses a “slower” implementation that needs to keep track of an object to keep the object live. This is not the case on modern runtimes where the GC allows it to track a ref directly. This is why creating the span like this can cause the object to be prematurely GC’d as the above code shows, and also why there’s no safe way to do this in NS2.0.

The usage of Unsafe.AsPointer however is still a problem on modern runtimes. If the GC runs the split moment after the call to AsPointer but before the span is constructed, the GC could move the backing object without updating the unmanaged pointer (depending on how aggressive the JIT is with tracking locals this might also result in “object freed prematurely” though).

Also if you use this value array in a local, you can return the span up the stack and the language won’t tell you, allowing you to access garbage memory.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Course Tour
Inspired by the “punch bowl” green at Chicago Golf Club, the green on the third hole is hidden with a carefully thought out...
Read more >
Boise Golf Rates - Shadow Valley Golf Club
18 Holes - $52.83/ 9 Holes $38.68 (9 hole rate available after 3pm) Super Twilight $27 all you can play after 5pm, does...
Read more >
Beaver Creek Golf Club | Golf Course | Grimes, IA
We offer 27 holes of great golf! All three of our nine hole courses are unique in their design. Our driving range is...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found