git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH] git-compat-util(msvc): C11 does not imply support for zero-sized arrays

From
PWPhillip Wood <phillip.wood123@gmail.com>
Date
Dec 9, 2021, 11:00 UTC
Message-ID
<f245f2b7-ca00-5497-3d1d-658c4c0fbcb6@gmail.com>
In-Reply-To
<nycvar.QRO.7.76.6.2112072217280.90@tvgsbejvaqbjf.bet>
Hi Dscho
On 07/12/2021 21:33, Johannes Schindelin wrote:
Show 18 quoted lines
> Hi Neeraj,
> 
> On Mon, 6 Dec 2021, Neeraj Singh wrote:
> 
>> I'm a little confused by this issue. Looks like an empty flex array
>> is supported here: https://godbolt.org/z/j3ndYTEfx.
> 
> It is somewhat strange, but understandable, that the empty flex array at
> the end of a struct isn't triggering a compile error. But having a field
> _after_ that empty flex array _does_ trigger a compile error:
> 
> struct MyStruct {
>      int x;
>      int flexA[];
>      char string[256];
> };
> 
> Note the added `string` field.
Having a field after the flex array is a violation of the C standard. 
Section 6.7.2.1:
    ... the last member of a structure with more than one named member
    may have incomplete array type, such a structure (and any union
    containing, possibly recursively, a member that is such a structure)
    shall not be a member of a structure or an element of an array.
Note that the wording also forbids
struct A {
	int x;
	char flex[];
};
struct B {
	struct A a; /* This is forbidden */
};

There was a proposal a few years ago to relax that restriction [1] but it does not seem to be in the latest draft standard.

None of this helps fix the problem, but it does explain why MSVC complains.
Best Wishes
Phillip
[1] http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2083.htm
Show 84 quoted lines
> See https://godbolt.org/z/TbcYhEW5d, it says:
> 
> 	<source>(5): error C2229: struct 'MyStruct' has an illegal zero-sized array
> 	Compiler returned: 2
> 
>> (Note that I'm passing /TC to force C compilation).
> 
> Yes, `/TC` is one of the flags we pass to MSVC. For more details, see
> https://github.com/git-for-windows/git/runs/4389081542?check_suite_focus=true#step:9:125
> 
>> Also, heap_fsentry doesn't appear to use a flex array in current sources.
> 
> It does, but it is admittedly a bit convoluted and not very easy to see.
> The definition of `heap_fsentry` is
> [this](https://github.com/git-for-windows/git/blob/v2.34.1.windows.1/compat/win32/fscache.c#L77-L80):
> 
> 	struct heap_fsentry {
> 		struct fsentry ent;
> 		char dummy[MAX_LONG_PATH];
> 	};
> 
> No flex array here, right? But wait, there is a `struct fsentry`. Let's
> look at
> [that](https://github.com/git-for-windows/git/blob/v2.34.1.windows.1/compat/win32/fscache.c#L43-L74):
> 
> 	struct fsentry {
> 		struct hashmap_entry ent;
> 		[...]
> 		/*
> 		 * Name of the entry. For directory listings: relative path of the
> 		 * directory, without trailing '/' (empty for cwd()). For file
> 		 * entries:
> 		 * name of the file. Typically points to the end of the structure
> 		 * if
> 		 * the fsentry is allocated on the heap (see fsentry_alloc), or to
> 		 * a
> 		 * local variable if on the stack (see fsentry_init).
> 		 */
> 		struct dirent dirent;
> 	};
> 
> Still no flex array, right? But wait, there is a `struct dirent`. Let's
> [see](https://github.com/git-for-windows/git/blob/v2.34.1.windows.1/compat/win32/dirent.h#L9-L12):
> 
> 	struct dirent {
> 		unsigned char d_type; /* file type to prevent lstat after readdir */
> 		char d_name[FLEX_ARRAY]; /* file name */
> 	};
> 
> Finally! We see the flex array.
> 
> Now, you may ask why is this even correct? How can you have an empty-sized
> field in a struct that is inside another struct that is inside yet another
> struct _and then followed by another field_?
> 
> The reason why this is correct and intended is that `struct dirent`
> intentionally leaves the length of the `d_name` undefined, to leave it to
> the implementation whether a fixed-size buffer is used or a
> specifically-allocated one of the exact correct size for a _specific_
> directory entry.
> 
> In FSCache, we want to allocate a large-enough buffer to fit _any_ file
> name, and it should not only contain the metadata in `struct dirent`, but
> additionally some FSCache-specific metadata.
> 
> Therefore, `struct fsentry` is kind of a subclass of `struct dirent`, and
> `struct heap_fsentry` is kind of a subclass of something that does not
> exist, a `struct dirent` that offers enough space to fit _any_ legal
> `d_name` (that is what that `dummy` field is for, it is not actually
> intended to be accessed except via `d_name`).
> 
>> If it does start using it, there issue may actually be elsewhere besides
>> the struct definition (it could be just a badly targeted compiler error).
>> We have code like `struct heap_fsentry key[2];`.  That declaration can't
>> work with a flex array.
> 
> I hope my explanation above made sense to you.
> 
> Admittedly, it is slightly icky code, but honestly, I do not have any
> splendid idea how to make it less complicated to understand. Do you?
> 
> Ciao,
> Dscho
> 
Previous: rsbecker@nexbridge.comNext: Junio C Hamano
Message 7 of 10 in “git-compat-util(msvc): C11 does not imply support for zero-sized arrays”
  1. git-compat-util(msvc): C11 does not imply support for zero-sized arraysJohannes Schindelin via GitGitGadget, Dec 6, 2021
  2. Junio C HamanoDec 6, 2021
  3. Neeraj SinghDec 6, 2021
  4. Johannes SchindelinDec 7, 2021
  5. Neeraj SinghDec 7, 2021
  6. rsbecker@nexbridge.comDec 7, 2021
  7. Phillip WoodDec 9, 2021
  8. Junio C HamanoDec 9, 2021
  9. Junio C HamanoDec 9, 2021
  10. Neeraj SinghDec 9, 2021

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.