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]; +} + /* * Return human readable string for size @val. * @val can be anything that uint64_t allows (no more than "16 EiB"). -- 2.55.0
