diff mbox series

[04/22] reftable/basics: handle allocation failures in `reftable_calloc()`

Message ID e6ded75f630ea309d5b76126560a0ec3d526bf71.1726489647.git.ps@pks.im (mailing list archive)
State Superseded
Headers show
Series reftable: handle allocation errors | expand

Commit Message

Patrick Steinhardt Sept. 16, 2024, 12:28 p.m. UTC
Handle allocation failures in `reftable_calloc()`.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 reftable/basics.c | 2 ++
 1 file changed, 2 insertions(+)

Comments

Junio C Hamano Sept. 21, 2024, 7:37 p.m. UTC | #1
Patrick Steinhardt <ps@pks.im> writes:

> Handle allocation failures in `reftable_calloc()`.
>
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>  reftable/basics.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/reftable/basics.c b/reftable/basics.c
> index 4adc98cf5de..b404900b5d9 100644
> --- a/reftable/basics.c
> +++ b/reftable/basics.c
> @@ -39,6 +39,8 @@ void *reftable_calloc(size_t nelem, size_t elsize)
>  {
>  	size_t sz = st_mult(nelem, elsize);
>  	void *p = reftable_malloc(sz);
> +	if (!p)
> +		return NULL;
>  	memset(p, 0, sz);
>  	return p;
>  }

Since this series is not about eradicating all avenues in reftable
library code that can lead to die(), but only about dealing with
allocation errors from the underlying malloc/realloc routines, I
think the code posted is perfectly fine as-is as a part of this
series, but since I noticed something, let me comment before I
forget.

When st_mult() detects overflow, you'd still die(), wouldn't you?

We'd probably want a variant of st_mult() that lets us notice a
condition that would yield too large a result, and code the above
like so,

	size_t sz;
	void *p;

	if (st_mult_gently(nelem, elsize, &sz) ||
            !((p = reftable_malloc(sz))))
		return NULL;
	memset(p, 0, sz);
	return p;

or use the underlying helper ourselves, and say

	size_t sz;
	void *p;

	if (unsigned_mult_overflows(nelem, elsize)) ||
            !((sz = nelem * elsize, p = reftable_malloc(sz))))
		return NULL;
	memset(p, 0, sz);
	return p;

which lets us without an extra helper but after writing it myself, I
find it a bit too wordy.

In a sense, it is on the borderline to handle st_mult() overflow in
this function for a topic whose theme is about allocation failures.

From the point of view of callers of reftable_calloc(), whether the
arguments they are feeding the function is too large to be
multiplied or whether the request is too big for the underlying
allocator to handle, the end result should be the same: they
requested too large an allocation.

So I wouldn't complain that it is out of scope, if use of st_mult()
that computes the allocation size is fixed as part of this series.
But as I already said, I am also OK if we leave it to a separate
series to tackle other potential callers of die().

Thanks.
Patrick Steinhardt Sept. 24, 2024, 5:48 a.m. UTC | #2
On Sat, Sep 21, 2024 at 12:37:26PM -0700, Junio C Hamano wrote:
> Patrick Steinhardt <ps@pks.im> writes:
> 
> > Handle allocation failures in `reftable_calloc()`.
> >
> > Signed-off-by: Patrick Steinhardt <ps@pks.im>
> > ---
> >  reftable/basics.c | 2 ++
> >  1 file changed, 2 insertions(+)
> >
> > diff --git a/reftable/basics.c b/reftable/basics.c
> > index 4adc98cf5de..b404900b5d9 100644
> > --- a/reftable/basics.c
> > +++ b/reftable/basics.c
> > @@ -39,6 +39,8 @@ void *reftable_calloc(size_t nelem, size_t elsize)
> >  {
> >  	size_t sz = st_mult(nelem, elsize);
> >  	void *p = reftable_malloc(sz);
> > +	if (!p)
> > +		return NULL;
> >  	memset(p, 0, sz);
> >  	return p;
> >  }
> 
> Since this series is not about eradicating all avenues in reftable
> library code that can lead to die(), but only about dealing with
> allocation errors from the underlying malloc/realloc routines, I
> think the code posted is perfectly fine as-is as a part of this
> series, but since I noticed something, let me comment before I
> forget.
> 
> When st_mult() detects overflow, you'd still die(), wouldn't you?

True.

> We'd probably want a variant of st_mult() that lets us notice a
> condition that would yield too large a result, and code the above
> like so,
> 
> 	size_t sz;
> 	void *p;
> 
> 	if (st_mult_gently(nelem, elsize, &sz) ||
>             !((p = reftable_malloc(sz))))
> 		return NULL;
> 	memset(p, 0, sz);
> 	return p;
> 
> or use the underlying helper ourselves, and say
> 
> 	size_t sz;
> 	void *p;
> 
> 	if (unsigned_mult_overflows(nelem, elsize)) ||
>             !((sz = nelem * elsize, p = reftable_malloc(sz))))
> 		return NULL;
> 	memset(p, 0, sz);
> 	return p;
> 
> which lets us without an extra helper but after writing it myself, I
> find it a bit too wordy.

Yeah, we'll have to have something like this eventually.

> In a sense, it is on the borderline to handle st_mult() overflow in
> this function for a topic whose theme is about allocation failures.
> 
> From the point of view of callers of reftable_calloc(), whether the
> arguments they are feeding the function is too large to be
> multiplied or whether the request is too big for the underlying
> allocator to handle, the end result should be the same: they
> requested too large an allocation.
> 
> So I wouldn't complain that it is out of scope, if use of st_mult()
> that computes the allocation size is fixed as part of this series.
> But as I already said, I am also OK if we leave it to a separate
> series to tackle other potential callers of die().

I'd leave it as-is for now, but I do have it on my agenda to address
this, as well. I already have it as part of my third patch series in
this context where I completely detangle the reftable library from the
rest of Git to make it a reusable library for libgit2 and the likes.

In any case, there's another, bigger elephant in the room: `struct
strbuf`. I will have to introduce a reftable-specific buffer type for
this such that we can handle allocation failures here, too. While the
alternative would be to amend `struct strbuf` itself to do that, I don't
quite think that we should do it in "core" Git itself for now. And it is
another excuse for me for why the reftable code should have its own type
instead of relying on `struct strbuf` in the context of making it a
standalone library again.

Patrick
Patrick Steinhardt Sept. 24, 2024, 6:02 a.m. UTC | #3
On Tue, Sep 24, 2024 at 07:48:57AM +0200, Patrick Steinhardt wrote:
> On Sat, Sep 21, 2024 at 12:37:26PM -0700, Junio C Hamano wrote:
> > Patrick Steinhardt <ps@pks.im> writes:
> > In a sense, it is on the borderline to handle st_mult() overflow in
> > this function for a topic whose theme is about allocation failures.
> > 
> > From the point of view of callers of reftable_calloc(), whether the
> > arguments they are feeding the function is too large to be
> > multiplied or whether the request is too big for the underlying
> > allocator to handle, the end result should be the same: they
> > requested too large an allocation.
> > 
> > So I wouldn't complain that it is out of scope, if use of st_mult()
> > that computes the allocation size is fixed as part of this series.
> > But as I already said, I am also OK if we leave it to a separate
> > series to tackle other potential callers of die().
> 
> I'd leave it as-is for now, but I do have it on my agenda to address
> this, as well. I already have it as part of my third patch series in
> this context where I completely detangle the reftable library from the
> rest of Git to make it a reusable library for libgit2 and the likes.

Well, you know. I reroll the series anyway, so I'll just make the change
now.

Patrick
Junio C Hamano Sept. 24, 2024, 4:39 p.m. UTC | #4
Patrick Steinhardt <ps@pks.im> writes:

> In any case, there's another, bigger elephant in the room: `struct
> strbuf`. I will have to introduce a reftable-specific buffer type for
> this such that we can handle allocation failures here, too.

Oh, that one.

If you are letting your callers to register allocation callbacks,
you'd want to make sure any code you use, in cluding strbuf, would
take pieces of memory from and return them to the registered
allocation routines.

> While the
> alternative would be to amend `struct strbuf` itself to do that, I don't
> quite think that we should do it in "core" Git itself for now.

Punting is of course an option, but what do the "libification" folks
want to see happen (Emily Cc'ed, not necessarily because she
personally did work in libification, but she knows who is responding
to the list this week)?  Wouldn't we eventually want these common
things not to die but to gracefully fail?
diff mbox series

Patch

diff --git a/reftable/basics.c b/reftable/basics.c
index 4adc98cf5de..b404900b5d9 100644
--- a/reftable/basics.c
+++ b/reftable/basics.c
@@ -39,6 +39,8 @@  void *reftable_calloc(size_t nelem, size_t elsize)
 {
 	size_t sz = st_mult(nelem, elsize);
 	void *p = reftable_malloc(sz);
+	if (!p)
+		return NULL;
 	memset(p, 0, sz);
 	return p;
 }