mirror of
https://gitlab.freedesktop.org/pipewire/pipewire
synced 2024-07-21 02:05:38 +00:00
spa: fix integer overflows etc. in spa_pod_compare_value
Add macro SPA_CMP to do 3-way comparisons safely, and use it to avoid signed integer overflows. Fix also float/double comparisons (previously 0.1 == 0.8 since cast to return type int). Fix Id/Bool comparisons so they can return negative value.
This commit is contained in:
parent
b94d6e53a1
commit
a63aa6329b
|
@ -31,16 +31,17 @@ static inline int spa_pod_compare_value(uint32_t type, const void *r1, const voi
|
||||||
case SPA_TYPE_None:
|
case SPA_TYPE_None:
|
||||||
return 0;
|
return 0;
|
||||||
case SPA_TYPE_Bool:
|
case SPA_TYPE_Bool:
|
||||||
|
return SPA_CMP(!!*(int32_t *)r1, !!*(int32_t *)r2);
|
||||||
case SPA_TYPE_Id:
|
case SPA_TYPE_Id:
|
||||||
return *(uint32_t *) r1 == *(uint32_t *) r2 ? 0 : 1;
|
return SPA_CMP(*(uint32_t *)r1, *(uint32_t *)r2);
|
||||||
case SPA_TYPE_Int:
|
case SPA_TYPE_Int:
|
||||||
return *(int32_t *) r1 - *(int32_t *) r2;
|
return SPA_CMP(*(int32_t *)r1, *(int32_t *)r2);
|
||||||
case SPA_TYPE_Long:
|
case SPA_TYPE_Long:
|
||||||
return *(int64_t *) r1 - *(int64_t *) r2;
|
return SPA_CMP(*(int64_t *)r1, *(int64_t *)r2);
|
||||||
case SPA_TYPE_Float:
|
case SPA_TYPE_Float:
|
||||||
return *(float *) r1 - *(float *) r2;
|
return SPA_CMP(*(float *)r1, *(float *)r2);
|
||||||
case SPA_TYPE_Double:
|
case SPA_TYPE_Double:
|
||||||
return *(double *) r1 - *(double *) r2;
|
return SPA_CMP(*(double *)r1, *(double *)r2);
|
||||||
case SPA_TYPE_String:
|
case SPA_TYPE_String:
|
||||||
return strcmp((char *)r1, (char *)r2);
|
return strcmp((char *)r1, (char *)r2);
|
||||||
case SPA_TYPE_Bytes:
|
case SPA_TYPE_Bytes:
|
||||||
|
@ -60,15 +61,10 @@ static inline int spa_pod_compare_value(uint32_t type, const void *r1, const voi
|
||||||
{
|
{
|
||||||
const struct spa_fraction *f1 = (struct spa_fraction *) r1,
|
const struct spa_fraction *f1 = (struct spa_fraction *) r1,
|
||||||
*f2 = (struct spa_fraction *) r2;
|
*f2 = (struct spa_fraction *) r2;
|
||||||
int64_t n1, n2;
|
uint64_t n1, n2;
|
||||||
n1 = ((int64_t) f1->num) * f2->denom;
|
n1 = ((uint64_t) f1->num) * f2->denom;
|
||||||
n2 = ((int64_t) f2->num) * f1->denom;
|
n2 = ((uint64_t) f2->num) * f1->denom;
|
||||||
if (n1 < n2)
|
return SPA_CMP(n1, n2);
|
||||||
return -1;
|
|
||||||
else if (n1 > n2)
|
|
||||||
return 1;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -186,6 +186,16 @@ struct spa_fraction {
|
||||||
x; \
|
x; \
|
||||||
})
|
})
|
||||||
|
|
||||||
|
/** 3-way comparison. NaN > NaN and NaN > finite numbers */
|
||||||
|
#define SPA_CMP(a, b) \
|
||||||
|
({ \
|
||||||
|
__typeof__(a) _a = (a); \
|
||||||
|
__typeof__(b) _b = (b); \
|
||||||
|
(_a > _b) ? 1 : (_a == _b) ? 0 : (_a < _b) ? -1 \
|
||||||
|
: (_a == _a) ? -1 : (_b == _b) ? 1 \
|
||||||
|
: 1; \
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the address (buffer + offset) as pointer of \a type
|
* Return the address (buffer + offset) as pointer of \a type
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <locale.h>
|
#include <locale.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
#include <valgrind/valgrind.h>
|
#include <valgrind/valgrind.h>
|
||||||
|
|
||||||
|
@ -150,6 +151,13 @@ PWTEST(utils_macros)
|
||||||
pwtest_int_eq(SPA_CLAMP(-1, 1, 16), 1);
|
pwtest_int_eq(SPA_CLAMP(-1, 1, 16), 1);
|
||||||
pwtest_int_eq(SPA_CLAMP(8, 1, 16), 8);
|
pwtest_int_eq(SPA_CLAMP(8, 1, 16), 8);
|
||||||
|
|
||||||
|
pwtest_int_eq(SPA_CMP(INT64_MAX, INT64_MIN), 1);
|
||||||
|
pwtest_int_eq(SPA_CMP(INT64_MIN, INT64_MAX), -1);
|
||||||
|
pwtest_int_eq(SPA_CMP(INT64_MAX, INT64_MAX), 0);
|
||||||
|
pwtest_int_eq(SPA_CMP(1, nan("")), -1);
|
||||||
|
pwtest_int_eq(SPA_CMP(nan(""), 1), 1);
|
||||||
|
pwtest_int_eq(SPA_CMP(nan(""), nan("")), 1);
|
||||||
|
|
||||||
/* SPA_MEMBER exists for backwards compatibility but should no
|
/* SPA_MEMBER exists for backwards compatibility but should no
|
||||||
* longer be used, let's make sure it does what we expect it to */
|
* longer be used, let's make sure it does what we expect it to */
|
||||||
pwtest_ptr_eq(SPA_MEMBER(ptr, 4, void), SPA_PTROFF(ptr, 4, void));
|
pwtest_ptr_eq(SPA_MEMBER(ptr, 4, void), SPA_PTROFF(ptr, 4, void));
|
||||||
|
|
Loading…
Reference in a new issue