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
Johannes Schindelin <johannes.schindelin@gmx.de>
Date
Dec 7, 2021, 21:33 UTC
Message-ID
<nycvar.QRO.7.76.6.2112072217280.90@tvgsbejvaqbjf.bet>
In-Reply-To
<20211206222539.GA27821@neerajsi-x1.localdomain>
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.
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: Neeraj SinghNext: Neeraj Singh
Message 4 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.