[v2,2/3] u_dynarray: return 0 on realloc failure and ensure no-op

Submitted by Nicolai Hähnle on May 13, 2019, 2:58 p.m.

Details

Message ID 20190513145808.11024-3-nhaehnle@gmail.com
State New
Headers show
Series "u_dynarray: minor API cleanups" ( rev: 2 ) in Mesa

Not browsing as part of any series.

Commit Message

Nicolai Hähnle May 13, 2019, 2:58 p.m.
From: Nicolai Hähnle <nicolai.haehnle@amd.com>

We're not very good at handling out-of-memory conditions in general, but
this change at least gives the caller the option of handling it gracefully
and without memory leaks.

This happens to fix an error in out-of-memory handling in i965, which has
the following code in brw_bufmgr.c:

      node = util_dynarray_grow(vma_list, sizeof(struct vma_bucket_node));
      if (unlikely(!node))
         return 0ull;

Previously, allocation failure for util_dynarray_grow wouldn't actually
return NULL when the dynarray was previously non-empty.

v2:
- make util_dynarray_ensure_cap a no-op on failure, add MUST_CHECK attribute
- simplify the new capacity calculation: aside from avoiding a useless loop
  when newcap is very large, this also avoids an infinite loop when newcap
  is larger than 1 << 31
---
 src/util/u_dynarray.h | 18 ++++++++++--------
 1 file changed, 10 insertions(+), 8 deletions(-)

Patch hide | download patch | download mbox

diff --git a/src/util/u_dynarray.h b/src/util/u_dynarray.h
index b30fd7b1154..769c3820546 100644
--- a/src/util/u_dynarray.h
+++ b/src/util/u_dynarray.h
@@ -70,35 +70,37 @@  util_dynarray_fini(struct util_dynarray *buf)
 }
 
 static inline void
 util_dynarray_clear(struct util_dynarray *buf)
 {
 	buf->size = 0;
 }
 
 #define DYN_ARRAY_INITIAL_SIZE 64
 
-static inline void *
+MUST_CHECK static inline void *
 util_dynarray_ensure_cap(struct util_dynarray *buf, unsigned newcap)
 {
    if (newcap > buf->capacity) {
-      if (buf->capacity == 0)
-         buf->capacity = DYN_ARRAY_INITIAL_SIZE;
-
-      while (newcap > buf->capacity)
-         buf->capacity *= 2;
+      unsigned capacity = MAX3(DYN_ARRAY_INITIAL_SIZE, buf->capacity * 2, newcap);
+      void *data;
 
       if (buf->mem_ctx) {
-         buf->data = reralloc_size(buf->mem_ctx, buf->data, buf->capacity);
+         data = reralloc_size(buf->mem_ctx, buf->data, capacity);
       } else {
-         buf->data = realloc(buf->data, buf->capacity);
+         data = realloc(buf->data, capacity);
       }
+      if (!data)
+         return 0;
+
+      buf->data = data;
+      buf->capacity = capacity;
    }
 
    return (void *)((char *)buf->data + buf->size);
 }
 
 static inline void *
 util_dynarray_grow_cap(struct util_dynarray *buf, int diff)
 {
    return util_dynarray_ensure_cap(buf, buf->size + diff);
 }