microsoft / microsoft/CsWin32

structs with VariableLengthInlineArray and SizeOf(0)

Open
#1,179 5 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
C#
Stars
2.5k
Forks
124
Avg merge
1d 3h
Merged PRs (30d)
9

Description

C structures with a flexible array member at the end (array of [0] elements) get translated to a VariableLengthInLineArray. As an example, I take USB_DESCRIPTOR_REQUEST, which in C is:

typedef struct _USB_DESCRIPTOR_REQUEST {
    ULONG ConnectionIndex;
    struct {
        UCHAR bmRequest;
        UCHAR bRequest;
        USHORT wValue;
        USHORT wIndex;
        USHORT wLength;
    } SetupPacket;
    UCHAR Data[0];
} USB_DESCRIPTOR_REQUEST, *PUSB_DESCRIPTOR_REQUEST;

I know about the discussion that in C# (using CsWin32) the VariableLengthInLineArray always has 1 member (as if UCHAR Data[1] instead of UCHAR Data[0]), and therefore the sizeof(C# struct) does not match the sizeof(C struct). And that's OK, since we now have a convenience member function SizeOf for such structures that takes a count parameter for the real number of elements in the array.

However, the function is defined as:

/// <summary>Computes the amount of memory that must be allocated to store this struct, including the specified number of elements in the variable length inline array at the end.</summary>
internal static unsafe int SizeOf(int count)
{
	int v = sizeof(USB_DESCRIPTOR_REQUEST);
	if (count > 1)
		v +=checked((count - 1) * sizeof(byte));
		else
			if (count < 0)
				throw new ArgumentOutOfRangeException();
	return v;
}

This does not return the correct size for 0; SizeOf(0) is still off by 1 array element. In fact SizeOf(0) == SizeOf(1) in the current implementation. Note that for the example USB_DESCRIPTOR_REQUEST, 0 is actually a valid size for the array (as in: the data is optional).

I don't know if this is deliberate, or actually a bug.

Could SizeOf(0) be changed so it returns sizeof(C# struct) - sizeof(the 1 element in VariableLengthInLineArray) == sizeof(C struct)? Something like:

/// <summary>Computes the amount of memory that must be allocated to store this struct, including the specified number of elements in the variable length inline array at the end.</summary>
internal static unsafe int SizeOf(int count)
{
	int v = sizeof(USB_DESCRIPTOR_REQUEST);
	if (count >= 0)
		// NOTE: the -1 for count == 0 is intentional, to compensate for the omnipresent 1 element in VariableLengthInLineArray
		v +=checked((count - 1) * sizeof(byte));
	else
		throw new ArgumentOutOfRangeException();
	return v;
}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by locating the generated USB_DESCRIPTOR_REQUEST SizeOf(int) implementation and the handling of VariableLengthInLineArray. Verify the current results for counts 0, 1, and greater values, then add or update coverage so SizeOf(0) matches the C flexible-array layout while negative counts remain invalid.

Written by the indexing model from the issue text.

Assessment

Tech stack
csharp
Domain
tooling
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.