summaryrefslogtreecommitdiffstats
path: root/options
diff options
context:
space:
mode:
authorKacper Michajłow <kasper93@gmail.com>2024-02-26 04:55:00 +0100
committerDudemanguy <random342@airmail.cc>2024-02-28 16:04:02 +0000
commit0897604298120c3f197fa151ff85c9b5213c26f6 (patch)
tree2c38308dce99430528ddf1c0746441ac8cdb7c42 /options
parentd955dfab294ecd24064f2d64b8af0bafc2af575c (diff)
downloadmpv-0897604298120c3f197fa151ff85c9b5213c26f6.tar.bz2
mpv-0897604298120c3f197fa151ff85c9b5213c26f6.tar.xz
various: avoid function pointer casts
The opt validator functions are casted to generic validator, which has erased type for value. Calling function by pointer of different definition is an UB. Avoid that by generating wrapper function that does proper argument type conversion and calls validator function. Type erased functions have mangled type in the name. Fixes UBSAN failures on Clang 17, which enabled fsanitize=function by default.
Diffstat (limited to 'options')
-rw-r--r--options/m_option.c5
-rw-r--r--options/m_option.h27
2 files changed, 17 insertions, 15 deletions
diff --git a/options/m_option.c b/options/m_option.c
index 47f9c07883..02dea2bf3c 100644
--- a/options/m_option.c
+++ b/options/m_option.c
@@ -61,11 +61,6 @@ const char m_option_path_separator = OPTION_PATH_SEPARATOR;
#define OPT_INT_MAX(opt, T, Tm) ((opt)->min < (opt)->max \
? ((opt)->max >= (double)(Tm) ? (Tm) : (T)((opt)->max)) : (Tm))
-#if defined(__clang__)
-// Last argument of validate functions is always a pointer, but not always void*
-// which triggers UBSAN warning.
-__attribute__((no_sanitize("function")))
-#endif
int m_option_parse(struct mp_log *log, const m_option_t *opt,
struct bstr name, struct bstr param, void *dst)
{
diff --git a/options/m_option.h b/options/m_option.h
index d818a367b7..891b51794e 100644
--- a/options/m_option.h
+++ b/options/m_option.h
@@ -189,15 +189,20 @@ struct m_opt_choice_alternatives {
const char *m_opt_choice_str(const struct m_opt_choice_alternatives *choices,
int value);
-// Validator function signatures. Required to properly type the param value.
typedef int (*m_opt_generic_validate_fn)(struct mp_log *log, const m_option_t *opt,
struct bstr name, void *value);
-typedef int (*m_opt_string_validate_fn)(struct mp_log *log, const m_option_t *opt,
- struct bstr name, const char **value);
-typedef int (*m_opt_int_validate_fn)(struct mp_log *log, const m_option_t *opt,
- struct bstr name, const int *value);
-
+#define OPT_FUNC(name) name
+#define OPT_FUNC_IN(name, suffix) name ## _ ## suffix
+#define OPT_VALIDATE_FUNC(func, value_type, suffix) \
+int OPT_FUNC(func)(struct mp_log *log, const m_option_t *opt, \
+ struct bstr name, value_type value); \
+static inline int OPT_FUNC_IN(func, suffix)(struct mp_log *log, const m_option_t *opt, \
+ struct bstr name, void *value) { \
+ return OPT_FUNC(func)(log, opt, name, value); \
+} \
+int OPT_FUNC(func)(struct mp_log *log, const m_option_t *opt, \
+ struct bstr name, value_type value)
// m_option.priv points to this if OPT_SUBSTRUCT is used
struct m_sub_options {
@@ -685,15 +690,17 @@ extern const char m_option_path_separator;
#define OPT_CHANNELS(field) \
OPT_TYPED_FIELD(m_option_type_channels, struct m_channels, field)
+#define OPT_INT_VALIDATE_FUNC(func) OPT_VALIDATE_FUNC(func, const int *, int)
+
#define OPT_INT_VALIDATE(field, validate_fn) \
OPT_TYPED_FIELD(m_option_type_int, int, field), \
- .validate = (m_opt_generic_validate_fn) \
- MP_EXPECT_TYPE(m_opt_int_validate_fn, validate_fn)
+ .validate = OPT_FUNC_IN(validate_fn, int)
+
+#define OPT_STRING_VALIDATE_FUNC(func) OPT_VALIDATE_FUNC(func, const char **, str)
#define OPT_STRING_VALIDATE(field, validate_fn) \
OPT_TYPED_FIELD(m_option_type_string, char*, field), \
- .validate = (m_opt_generic_validate_fn) \
- MP_EXPECT_TYPE(m_opt_string_validate_fn, validate_fn)
+ .validate = OPT_FUNC_IN(validate_fn, str)
#define M_CHOICES(...) \
.priv = (void *)&(const struct m_opt_choice_alternatives[]){ __VA_ARGS__, {0}}