driconf: add uint64 type

This is needed for panvk, where we want to expose uint64 core masks. The
previous int parsing logic was technically UB rather than guaranteed
truncate-on-overflow, but was likely compiled to truncate in practice.
It is very unlikely that anyone was relying on this.

Signed-off-by: Benjamin Lee <benjamin.lee@collabora.com>
Reviewed-by: Boris Brezillon <boris.brezillon@collabora.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/34374>
This commit is contained in:
Benjamin Lee 2025-03-17 14:28:11 -07:00 committed by Marge Bot
parent 141f0ef4e4
commit d46e76be02
3 changed files with 108 additions and 18 deletions

View file

@ -58,6 +58,12 @@
.end = { ._int = max }, \
} \
#define DRI_CONF_RANGE_U64(min, max) \
.range = { \
.start = { ._uint64 = min }, \
.end = { ._uint64 = max }, \
}
#define DRI_CONF_RANGE_F(min, max) \
.range = { \
.start = { ._float = min }, \
@ -88,6 +94,16 @@
.value = { ._int = def }, \
},
#define DRI_CONF_OPT_U64(_name, def, min, max, _desc) { \
.desc = _desc, \
.info = { \
.name = #_name, \
.type = DRI_UINT64, \
DRI_CONF_RANGE_U64(min, max), \
}, \
.value = { ._uint64 = def }, \
},
#define DRI_CONF_OPT_F(_name, def, min, max, _desc) { \
.desc = _desc, \
.info = { \

View file

@ -76,31 +76,35 @@ be_verbose(void)
return strstr(s, "silent") == NULL;
}
/** \brief Locale-independent integer parser.
/** \brief Locale-independent 64-bit integer parser.
*
* Works similar to strtol. Leading space is NOT skipped. The input
* number may have an optional sign. Radix is specified by base. If
* base is 0 then decimal is assumed unless the input number is
* prefixed by 0x or 0X for hexadecimal or 0 for octal. After
* returning tail points to the first character that is not part of
* the integer number. If no number was found then tail points to the
* start of the input string. */
static int
strToI(const char *string, const char **tail, int base)
* Works similar to strtol. Leading space is NOT skipped. If the sign
* argument is non-null, the input number may have an optional sign.
* Radix is specified by base. If base is 0 then decimal is assumed
* unless the input number is prefixed by 0x or 0X for hexadecimal or
* 0 for octal. After returning tail points to the first character
* that is not part of the integer number. If no number was found then
* tail points to the start of the input string. Out-of-range values
* are truncated. */
static uint64_t
strToInteger(const char *string, const char **tail, int *sign, int base)
{
int radix = base == 0 ? 10 : base;
int result = 0;
int sign = 1;
uint64_t result = 0;
bool numberFound = false;
const char *start = string;
assert(radix >= 2 && radix <= 36);
if (*string == '-') {
sign = -1;
string++;
} else if (*string == '+')
string++;
if (sign) {
*sign = 1;
if (*string == '-') {
*sign = -1;
string++;
} else if (*string == '+')
string++;
}
if (base == 0 && *string == '0') {
numberFound = true;
if (*(string+1) == 'x' || *(string+1) == 'X') {
@ -132,9 +136,30 @@ strToI(const char *string, const char **tail, int base)
break;
} while (true);
*tail = numberFound ? string : start;
return result;
}
/** \brief Locale-independent integer parser.
*
* Follows the semantics of strToInteger, allowing a sign character. */
static int
strToI(const char *string, const char **tail, int base)
{
int sign;
int result = strToInteger(string, tail, &sign, base);
return sign * result;
}
/** \brief Locale-independent 64-bit unsigned integer parser.
*
* Follows the semantics of strToInteger, without allowing a sign
* character. */
static uint64_t
strToU64(const char *string, const char **tail, int base)
{
return strToInteger(string, tail, NULL, base);
}
/** \brief Locale-independent floating-point parser.
*
* Works similar to strtod. Leading space is NOT skipped. The input
@ -233,6 +258,9 @@ parseValue(driOptionValue *v, driOptionType type, const char *string)
case DRI_INT:
v->_int = strToI(string, &tail, 0);
break;
case DRI_UINT64:
v->_uint64 = strToU64(string, &tail, 0);
break;
case DRI_FLOAT:
v->_float = strToF(string, &tail);
break;
@ -303,6 +331,11 @@ checkValue(const driOptionValue *v, const driOptionInfo *info)
(v->_int >= info->range.start._int &&
v->_int <= info->range.end._int));
case DRI_UINT64:
return (info->range.start._uint64 == info->range.end._uint64 ||
(v->_uint64 >= info->range.start._uint64 &&
v->_uint64 <= info->range.end._uint64));
case DRI_FLOAT:
return (info->range.start._float == info->range.end._float ||
(v->_float >= info->range.start._float &&
@ -368,6 +401,10 @@ driParseOptionInfo(driOptionCache *info,
optval->_int = opt->value._int;
break;
case DRI_UINT64:
optval->_uint64 = opt->value._uint64;
break;
case DRI_FLOAT:
optval->_float = opt->value._float;
break;
@ -437,6 +474,7 @@ driGetOptionsXml(const driOptionDescription *configOptions, unsigned numOptions)
const char *types[] = {
[DRI_BOOL] = "bool",
[DRI_INT] = "int",
[DRI_UINT64] = "uint64",
[DRI_FLOAT] = "float",
[DRI_ENUM] = "enum",
[DRI_STRING] = "string",
@ -470,6 +508,10 @@ driGetOptionsXml(const driOptionDescription *configOptions, unsigned numOptions)
ralloc_asprintf_append(&str, "%d", opt->value._int);
break;
case DRI_UINT64:
ralloc_asprintf_append(&str, "%" PRIu64, opt->value._uint64);
break;
case DRI_FLOAT:
ralloc_asprintf_append(&str, "%f", opt->value._float);
break;
@ -495,6 +537,14 @@ driGetOptionsXml(const driOptionDescription *configOptions, unsigned numOptions)
}
break;
case DRI_UINT64:
if (opt->info.range.start._uint64 < opt->info.range.end._uint64) {
ralloc_asprintf_append(&str, " valid=\"%" PRIu64 ":%" PRIu64 "\"",
opt->info.range.start._uint64,
opt->info.range.end._uint64);
}
break;
case DRI_FLOAT:
if (opt->info.range.start._float < opt->info.range.end._float) {
ralloc_asprintf_append(&str, " valid=\"%f:%f\"",
@ -639,6 +689,11 @@ parseRange(driOptionInfo *info, const char *string)
free(cp);
return false;
}
if (info->type == DRI_UINT64 &&
info->range.start._uint64 >= info->range.end._uint64) {
free(cp);
return false;
}
if (info->type == DRI_FLOAT &&
info->range.start._float >= info->range.end._float) {
free(cp);
@ -1278,6 +1333,16 @@ driQueryOptioni(const driOptionCache *cache, const char *name)
return cache->values[i]._int;
}
uint64_t
driQueryOptionu64(const driOptionCache *cache, const char *name)
{
uint32_t i = findOption(cache, name);
/* make sure the option is defined and has the correct type */
assert(cache->info[i].name != NULL);
assert(cache->info[i].type == DRI_UINT64);
return cache->values[i]._uint64;
}
float
driQueryOptionf(const driOptionCache *cache, const char *name)
{

View file

@ -34,6 +34,7 @@
#include "util/ralloc.h"
#include <stdint.h>
#include <string.h>
#include <inttypes.h>
#ifdef __cplusplus
extern "C" {
@ -43,13 +44,14 @@ extern "C" {
/** \brief Option data types */
typedef enum driOptionType {
DRI_BOOL, DRI_ENUM, DRI_INT, DRI_FLOAT, DRI_STRING, DRI_SECTION
DRI_BOOL, DRI_ENUM, DRI_INT, DRI_UINT64, DRI_FLOAT, DRI_STRING, DRI_SECTION
} driOptionType;
/** \brief Option value */
typedef union driOptionValue {
unsigned char _bool; /**< \brief Boolean */
int _int; /**< \brief Integer or Enum */
uint64_t _uint64; /**< \brief Unsigned 64-bit Integer */
float _float; /**< \brief Floating-point */
char *_string; /**< \brief String */
} driOptionValue;
@ -153,6 +155,8 @@ unsigned char driCheckOption(const driOptionCache *cache, const char *name,
unsigned char driQueryOptionb(const driOptionCache *cache, const char *name);
/** \brief Query an integer option value */
int driQueryOptioni(const driOptionCache *cache, const char *name);
/** \brief Query a 64-bit unsigned integer option value */
uint64_t driQueryOptionu64(const driOptionCache *cache, const char *name);
/** \brief Query a floating-point option value */
float driQueryOptionf(const driOptionCache *cache, const char *name);
/** \brief Query a string option value */
@ -187,6 +191,11 @@ driComputeOptionsSha1(const driOptionCache *cache, unsigned char *sha1)
cache->info[i].name,
cache->values[i]._int);
break;
case DRI_UINT64:
ret = ralloc_asprintf_append(&dri_options, "%s:%" PRIu64 ",",
cache->info[i].name,
cache->values[i]._uint64);
break;
case DRI_FLOAT:
ret = ralloc_asprintf_append(&dri_options, "%s:%f,",
cache->info[i].name,