On 10/29/2026 5:19 AM, Richard Henderson wrote: > 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? >
It ensures array is a string array, and not any other type. _Generic could probably catch this also, with a more clunky syntax. > Otherwise, > Acked-by: Richard Henderson <[email protected]> > > r~ >
