On 10/22/26 16:50, Philippe Mathieu-Daudé wrote:
Many functions map an enum or exception number to a name, either
with a switch statement or by indexing a string table after an
open-coded bounds check. Add STR_ARRAY_ELEM_OR_NULL(array, index),
which returns array[index], or NULL when index is out of bounds,
so such code can use a static table and a single call.

The array is passed as 'const char *const *', so only arrays of
strings are accepted; hence the STR_ prefix rather than a generic
name.

Misuse is caught at build time:
- pointer instead of array: "negative width in bit-field" error,
   plus -Wsizeof-pointer-div (GCC);
- array of non-strings (int[], char[][N], int *[]):
   -Wincompatible-pointer-types;
- array of non-const 'char *': -Wincompatible-pointer-types (GCC),
   -Wincompatible-pointer-types-discards-qualifiers (clang);
- pointer as index: -Wint-conversion.

Suggested-by: Pierrick Bouvier <[email protected]>
Signed-off-by: Philippe Mathieu-Daudé <[email protected]>
---
  include/qemu/cutils.h | 17 +++++++++++++++++
  include/qemu/osdep.h  |  3 +++
  util/cutils.c         |  6 ++++++
  3 files changed, 26 insertions(+)

diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h
index d249f226766..ad4c778ea3a 100644
--- a/include/qemu/cutils.h
+++ b/include/qemu/cutils.h
@@ -19,6 +19,23 @@ const char *si_prefix(unsigned int exp10);
   */
  const char *iec_binary_prefix(unsigned int exp2);
+const char *str_array_elem_or_null(const char *const *array,
+                                   size_t nelem, uint64_t index);
+
+/**
+ * STR_ARRAY_ELEM_OR_NULL() - Return a string array element, or NULL if
+ *                            out of bounds
+ * @array: array of strings to index
+ * @index: index of the element to return
+ *
+ * Return @array[@index] if @index is a valid index, otherwise return
+ * NULL. @index is converted to uint64_t, so negative values of signed
+ * types are out of bounds and also yield NULL. Useful to look up entries
+ * in enum-indexed string tables without a prior bounds check.
+ */
+#define STR_ARRAY_ELEM_OR_NULL(array, index) \
+    str_array_elem_or_null(array, ARRAY_SIZE(array), index)
+
  /**
   * pstrcpy:
   * @buf: buffer to copy string into
diff --git a/include/qemu/osdep.h b/include/qemu/osdep.h
index 5d5695ade28..50c7ce33b6a 100644
--- a/include/qemu/osdep.h
+++ b/include/qemu/osdep.h
@@ -532,6 +532,9 @@ void QEMU_ERROR("code path is reachable")
   * ARRAY_SIZE() - Return the number of elements of an array
   * @x: the array
   *
+ * For bounds-checked lookups in arrays of strings, see
+ * STR_ARRAY_ELEM_OR_NULL() in "qemu/cutils.h".
+ *
   * Note: fails to build if @x is a pointer.
   */
  #ifndef ARRAY_SIZE
diff --git a/util/cutils.c b/util/cutils.c
index 91ddadfd15a..d8a04ead5a4 100644
--- a/util/cutils.c
+++ b/util/cutils.c
@@ -954,6 +954,12 @@ const char *iec_binary_prefix(unsigned int exp2)
      return prefixes[exp2 / 10];
  }
+const char *str_array_elem_or_null(const char *const *array,
+                                   size_t nelem, uint64_t index)
+{
+    return index >= nelem ? NULL : array[index];
+}
Why is this trivial function out of line?

Otherwise,
Acked-by: Richard Henderson <[email protected]>

r~

Reply via email to