diff mbox series

[17/22] reftable/iter: handle allocation failures when creating indexed table iter

Message ID 32fead57de989335b17d16f63c1cd144460495a1.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:29 p.m. UTC
Handle allocation failures in `new_indexed_table_ref_iter()`. While at
it, rename the function to match our coding style.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 reftable/iter.c   | 22 ++++++++++++++++------
 reftable/iter.h   |  2 +-
 reftable/reader.c |  7 ++++++-
 3 files changed, 23 insertions(+), 8 deletions(-)

Comments

Junio C Hamano Sept. 22, 2024, 6:26 a.m. UTC | #1
Patrick Steinhardt <ps@pks.im> writes:

> -int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
> +int indexed_table_ref_iter_new(struct indexed_table_ref_iter **dest,
>  			       struct reftable_reader *r, uint8_t *oid,
>  			       int oid_len, uint64_t *offsets, int offset_len)
>  {
>  	struct indexed_table_ref_iter empty = INDEXED_TABLE_REF_ITER_INIT;
> -	struct indexed_table_ref_iter *itr = reftable_calloc(1, sizeof(*itr));
> +	struct indexed_table_ref_iter *itr;
>  	int err = 0;
>  
> +	itr = reftable_calloc(1, sizeof(*itr));
> +	if (!itr) {
> +		err = REFTABLE_OUT_OF_MEMORY_ERROR;
> +		goto out;
> +	}
> +
>  	*itr = empty;
>  	itr->r = r;
>  	strbuf_add(&itr->oid, oid, oid_len);
> @@ -197,11 +203,15 @@ int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
>  	itr->offset_len = offset_len;
>  
>  	err = indexed_table_ref_iter_next_block(itr);
> -	if (err < 0) {
> +	if (err < 0)
> +		goto out;
> +
> +	*dest = itr;
> +	err = 0;
> +
> +out:
> +	if (err < 0)
>  		reftable_free(itr);
> -	} else {
> -		*dest = itr;
> -	}
>  	return err;
>  }

Unless the service the helper function offers is to upgrade an
existing resource (e.g., realloc() taking a pointer and give an
enlarged piece of memory), it may be a safer calling convention to
promise that *dest is cleared to NULL when the function fails,
instead of promising that *dest is left intact.  The caller, when it
needs to evantually release the resource acquired here, has to
remember what the returned value (i.e., err) was, in order to decide
if it needs to call the release helper on *dest it obtained from us.

The only caller seems to initialize *dest to NULL itself, so it does
not matter in the current code, though.
Patrick Steinhardt Sept. 24, 2024, 5:49 a.m. UTC | #2
On Sat, Sep 21, 2024 at 11:26:09PM -0700, Junio C Hamano wrote:
> Patrick Steinhardt <ps@pks.im> writes:
> 
> > -int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
> > +int indexed_table_ref_iter_new(struct indexed_table_ref_iter **dest,
> >  			       struct reftable_reader *r, uint8_t *oid,
> >  			       int oid_len, uint64_t *offsets, int offset_len)
> >  {
> >  	struct indexed_table_ref_iter empty = INDEXED_TABLE_REF_ITER_INIT;
> > -	struct indexed_table_ref_iter *itr = reftable_calloc(1, sizeof(*itr));
> > +	struct indexed_table_ref_iter *itr;
> >  	int err = 0;
> >  
> > +	itr = reftable_calloc(1, sizeof(*itr));
> > +	if (!itr) {
> > +		err = REFTABLE_OUT_OF_MEMORY_ERROR;
> > +		goto out;
> > +	}
> > +
> >  	*itr = empty;
> >  	itr->r = r;
> >  	strbuf_add(&itr->oid, oid, oid_len);
> > @@ -197,11 +203,15 @@ int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
> >  	itr->offset_len = offset_len;
> >  
> >  	err = indexed_table_ref_iter_next_block(itr);
> > -	if (err < 0) {
> > +	if (err < 0)
> > +		goto out;
> > +
> > +	*dest = itr;
> > +	err = 0;
> > +
> > +out:
> > +	if (err < 0)
> >  		reftable_free(itr);
> > -	} else {
> > -		*dest = itr;
> > -	}
> >  	return err;
> >  }
> 
> Unless the service the helper function offers is to upgrade an
> existing resource (e.g., realloc() taking a pointer and give an
> enlarged piece of memory), it may be a safer calling convention to
> promise that *dest is cleared to NULL when the function fails,
> instead of promising that *dest is left intact.  The caller, when it
> needs to evantually release the resource acquired here, has to
> remember what the returned value (i.e., err) was, in order to decide
> if it needs to call the release helper on *dest it obtained from us.
> 
> The only caller seems to initialize *dest to NULL itself, so it does
> not matter in the current code, though.

I don't really see it as much of a problem here, mostly because this
function is internal to the reftable library anyway. Also, callers
essentially have to NULL-initialize the variable anyway once there are
multiple error paths and if they want to free it, because otherwise they
could end up freeing a uninitialized pointer.

On the other hand it doesn't hurt much to assign `NULL` on the error
path either, so I'll just do that.

Patrick
diff mbox series

Patch

diff --git a/reftable/iter.c b/reftable/iter.c
index 416a9f6996b..41bdfbb13f9 100644
--- a/reftable/iter.c
+++ b/reftable/iter.c
@@ -181,14 +181,20 @@  static int indexed_table_ref_iter_next(void *p, struct reftable_record *rec)
 	}
 }
 
-int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
+int indexed_table_ref_iter_new(struct indexed_table_ref_iter **dest,
 			       struct reftable_reader *r, uint8_t *oid,
 			       int oid_len, uint64_t *offsets, int offset_len)
 {
 	struct indexed_table_ref_iter empty = INDEXED_TABLE_REF_ITER_INIT;
-	struct indexed_table_ref_iter *itr = reftable_calloc(1, sizeof(*itr));
+	struct indexed_table_ref_iter *itr;
 	int err = 0;
 
+	itr = reftable_calloc(1, sizeof(*itr));
+	if (!itr) {
+		err = REFTABLE_OUT_OF_MEMORY_ERROR;
+		goto out;
+	}
+
 	*itr = empty;
 	itr->r = r;
 	strbuf_add(&itr->oid, oid, oid_len);
@@ -197,11 +203,15 @@  int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
 	itr->offset_len = offset_len;
 
 	err = indexed_table_ref_iter_next_block(itr);
-	if (err < 0) {
+	if (err < 0)
+		goto out;
+
+	*dest = itr;
+	err = 0;
+
+out:
+	if (err < 0)
 		reftable_free(itr);
-	} else {
-		*dest = itr;
-	}
 	return err;
 }
 
diff --git a/reftable/iter.h b/reftable/iter.h
index befc4597df1..b3225bc7add 100644
--- a/reftable/iter.h
+++ b/reftable/iter.h
@@ -82,7 +82,7 @@  void iterator_from_indexed_table_ref_iter(struct reftable_iterator *it,
 					  struct indexed_table_ref_iter *itr);
 
 /* Takes ownership of `offsets` */
-int new_indexed_table_ref_iter(struct indexed_table_ref_iter **dest,
+int indexed_table_ref_iter_new(struct indexed_table_ref_iter **dest,
 			       struct reftable_reader *r, uint8_t *oid,
 			       int oid_len, uint64_t *offsets, int offset_len);
 
diff --git a/reftable/reader.c b/reftable/reader.c
index f696e992dfc..0179e4e73dd 100644
--- a/reftable/reader.c
+++ b/reftable/reader.c
@@ -715,7 +715,7 @@  static int reftable_reader_refs_for_indexed(struct reftable_reader *r,
 		goto done;
 	}
 
-	err = new_indexed_table_ref_iter(&itr, r, oid, hash_size(r->hash_id),
+	err = indexed_table_ref_iter_new(&itr, r, oid, hash_size(r->hash_id),
 					 got.u.obj.offsets,
 					 got.u.obj.offset_len);
 	if (err < 0)
@@ -740,6 +740,11 @@  static int reftable_reader_refs_for_unindexed(struct reftable_reader *r,
 	int err;
 
 	REFTABLE_ALLOC_ARRAY(ti, 1);
+	if (!ti) {
+		err = REFTABLE_OUT_OF_MEMORY_ERROR;
+		goto out;
+	}
+
 	table_iter_init(ti, r);
 	err = table_iter_seek_start(ti, BLOCK_TYPE_REF, 0);
 	if (err < 0)