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

Re: [PATCH v2] mem-pool: Don't assume uintmax_t is aligned enough for all types

From
Junio C Hamano <gitster@pobox.com>
Date
Jan 23, 2022, 20:17 UTC
Message-ID
<xmqqsfte8awj.fsf@gitster.g>
In-Reply-To
<20220123152458.72540-1-jrtc27@jrtc27.com>
Jessica Clarke <jrtc27@jrtc27.com> writes:
> Currently mem_pool_alloc uses sizeof(uintmax_t) as a proxy for what
> should be _Alignof(max_align_t) in C11. On most architectures this is

Lose "Currently", as the present tense describes the status quo, the shape of the problematic code we have today that wants improvement by the proposed patch.

Show 6 quoted lines
> sufficient (though on m68k it is in fact overly strict, since the
> de-facto ABI, which differs from the specified System V ABI, has the
> maximum alignment of all types as 2 bytes), but on CHERI, and thus Arm's
> Morello prototype, it is insufficient for any type that stores a
> pointer, which must be aligned to 128 bits (on 64-bit architectures
> extended with CHERI), whilst uintmax_t is a 64-bit integer.
OK.
> Fix this by introducing our own approximation for max_align_t and a
> means to compute _Alignof it without relying on C11. Currently this
> union only contains uintmax_t and void *, but more types can be added as
> needed.
Nicely described.
Show 16 quoted lines
> +/*
> + * The inner union is an approximation for C11's max_align_t, and the
> + * struct + offsetof computes _Alignof. This can all just be replaced
> + * with _Alignof(max_align_t) if/when C11 is part of the baseline.
> + *
> + * Add more types to the union if the current set is insufficient.
> + */
> +struct git_max_alignment {
> +	char unalign;
> +	union {
> +		uintmax_t max_align_uintmax;
> +		void *max_align_pointer;
> +	} aligned;
> +};
> +#define GIT_MAX_ALIGNMENT offsetof(struct git_max_alignment, aligned)
> +

The original computed the alignment requirement for uintmax_t as sizeof(uintmax_t), not as

	offsetof(struct {
		char unalign;
		union { uintmax_t i; } aligned;
	}, aligned)

because if you have an array of a type, each element of it must be aligned appropriately already for that type, without the unalignment the outer struct enforces. I wonder if your complex offsetof is equivalent to sizeof(union { uintmax_t u; void *p; })?

IOW, in this struct:
	struct max_alignment_helper {
		char unalign;
		union {
			uintmax_t uintmax_t_unused;
			void *pointer_unused;
		} u[2];
	} s;

both s.u[0] and s.u[1] must be properly aligned, so wouldn't the alignment requirement for the union type, which can be used to hold a single value of either uintmax_t or a poinhter, be the distance between these two array elements, i.e. sizeof(s.u[0])?

To put it differently in yet another way, wouldn't it simplify down to this?

	union max_alignment_helper {
		uintmax_t uintmax_t_unused;
                void *pointer_unused;
	};
	#define GIT_MAX_ALIGNMENT sizeof(union max_alignment_helper);

I am not saying that the "a forcibly unaligned union in a struct" is a bad/wrong way to express what you want to achieve. I just do not know if there is a reason to choose it over a seemingly simpler sizeof(that union) without the outer struct and unalign member.

Other than that, looks OK to me. Especially the parts that use the macro look correctly converted.

Thanks.
Show 13 quoted lines
> @@ -69,9 +85,9 @@ void *mem_pool_alloc(struct mem_pool *pool, size_t len)
>  	struct mp_block *p = NULL;
>  	void *r;
>  
> -	/* round up to a 'uintmax_t' alignment */
> -	if (len & (sizeof(uintmax_t) - 1))
> -		len += sizeof(uintmax_t) - (len & (sizeof(uintmax_t) - 1));
> +	/* round up to a 'GIT_MAX_ALIGNMENT' alignment */
> +	if (len & (GIT_MAX_ALIGNMENT - 1))
> +		len += GIT_MAX_ALIGNMENT - (len & (GIT_MAX_ALIGNMENT - 1));
>  
>  	if (pool->mp_block &&
>  	    pool->mp_block->end - pool->mp_block->next_free >= len)
Show 16 quoted lines
>  /*
>   * Allocate a new mp_block and insert it after the block specified in
>   * `insert_after`. If `insert_after` is NULL, then insert block at the
> @@ -69,9 +85,9 @@ void *mem_pool_alloc(struct mem_pool *pool, size_t len)
>  	struct mp_block *p = NULL;
>  	void *r;
>  
> -	/* round up to a 'uintmax_t' alignment */
> -	if (len & (sizeof(uintmax_t) - 1))
> -		len += sizeof(uintmax_t) - (len & (sizeof(uintmax_t) - 1));
> +	/* round up to a 'GIT_MAX_ALIGNMENT' alignment */
> +	if (len & (GIT_MAX_ALIGNMENT - 1))
> +		len += GIT_MAX_ALIGNMENT - (len & (GIT_MAX_ALIGNMENT - 1));
>  
>  	if (pool->mp_block &&
>  	    pool->mp_block->end - pool->mp_block->next_free >= len)
Previous: Jessica ClarkeNext: Jessica Clarke
Message 28 of 32 in “Properly align memory allocations and temporary buffers”
  1. Properly align memory allocations and temporary buffersJessica Clarke, Jan 5, 2022
  2. Taylor BlauJan 6, 2022
  3. Jessica ClarkeJan 6, 2022
  4. Junio C HamanoJan 6, 2022
  5. Jessica ClarkeJan 6, 2022
  6. Junio C HamanoJan 7, 2022
  7. Jessica ClarkeJan 7, 2022
  8. brian m. carlsonJan 7, 2022
  9. Jessica ClarkeJan 7, 2022
  10. brian m. carlsonJan 7, 2022
  11. Jessica ClarkeJan 7, 2022
  12. Jessica ClarkeJan 7, 2022
  13. Junio C HamanoJan 7, 2022
  14. Jessica ClarkeJan 7, 2022
  15. René ScharfeJan 7, 2022
  16. Junio C HamanoJan 7, 2022
  17. René ScharfeJan 7, 2022
  18. Elijah NewrenJan 8, 2022
  19. brian m. carlsonJan 6, 2022
  20. Jessica ClarkeJan 6, 2022
  21. Philip OakleyJan 7, 2022
  22. René ScharfeJan 7, 2022
  23. Jessica ClarkeJan 7, 2022
  24. Jessica ClarkeJan 12, 2022
  25. René ScharfeJan 12, 2022
  26. Jessica ClarkeJan 12, 2022
  27. mem-pool: Don't assume uintmax_t is aligned enough for all typesJessica Clarke, Jan 23, 2022
  28. Junio C HamanoJan 23, 2022
  29. Jessica ClarkeJan 23, 2022
  30. Junio C HamanoJan 23, 2022
  31. mem-pool: Don't assume uintmax_t is aligned enough for all typesJessica Clarke, Jan 23, 2022
  32. Junio C HamanoJan 24, 2022

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.