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~
> 


Reply via email to