Fix failed assertion in guf_str_copy

An assertion GUF_ASSERT(str_is_valid(dst)) failed in guf_str_copy when it called guf_str_cstr(dst)
 since guf_str_cstr assumes an already valid string, which was not the case when src was a short string.

Therefore, we get the dst's c_str now without calling guf_str_cstr(dst)

(Found by writing DbufStrTest.)
This commit is contained in:
jun 2025-05-15 20:53:50 +02:00
parent 7585848ac9
commit 614a9716cc
8 changed files with 767 additions and 12 deletions

View File

@ -81,12 +81,21 @@
typedef enum guf_math_ckd_result {GUF_MATH_CKD_SUCCESS = 0, GUF_MATH_CKD_OVERFLOW_POS, GUF_MATH_CKD_OVERFLOW_NEG} guf_math_ckd_result;
#if !defined(GUF_MATH_CKDINT_IMPL_STATIC) && !defined(GUF_MATH_CKDINT_IMPL)
// Signed integer arithmetic checks (generated with libguf/tools/ckdint-gen.py)
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_int(int a, int b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_int(int a, int b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_int(int a, int b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_long(long a, long b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_long(long a, long b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_long(long a, long b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_long_long(long long a, long long b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_long_long(long long a, long long b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_long_long(long long a, long long b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_i8(int8_t a, int8_t b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_i8(int8_t a, int8_t b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_i8(int8_t a, int8_t b);
@ -117,6 +126,14 @@ GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_unsigned(unsigned a, unsig
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_unsigned(unsigned a, unsigned b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_unsigned(unsigned a, unsigned b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_ulong(unsigned long a, unsigned long b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_ulong(unsigned long a, unsigned long b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_ulong(unsigned long a, unsigned long b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_ulong_long(unsigned long long a, unsigned long long b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_ulong_long(unsigned long long a, unsigned long long b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_ulong_long(unsigned long long a, unsigned long long b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_u8(uint8_t a, uint8_t b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_u8(uint8_t a, uint8_t b);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_u8(uint8_t a, uint8_t b);
@ -149,6 +166,24 @@ GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_int(int a, int b, int
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_int(int a, int b, int *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_long(long a, long b, long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_long(long a, long b, long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_long(long a, long b, long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_long(long a, long b, long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_long(long a, long b, long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_long(long a, long b, long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_long_long(long long a, long long b, long long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_long_long(long long a, long long b, long long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_long_long(long long a, long long b, long long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_long_long(long long a, long long b, long long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_long_long(long long a, long long b, long long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_long_long(long long a, long long b, long long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_i8(int8_t a, int8_t b, int8_t *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_i8(int8_t a, int8_t b, int8_t *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_i8(int8_t a, int8_t b, int8_t *result);
@ -214,6 +249,24 @@ GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_unsigned(unsigned a,
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_unsigned(unsigned a, unsigned b, unsigned *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_ulong(unsigned long a, unsigned long b, unsigned long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_ulong(unsigned long a, unsigned long b, unsigned long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_ulong(unsigned long a, unsigned long b, unsigned long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_ulong(unsigned long a, unsigned long b, unsigned long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_ulong(unsigned long a, unsigned long b, unsigned long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_ulong(unsigned long a, unsigned long b, unsigned long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_ulong_long(unsigned long long a, unsigned long long b, unsigned long long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_ulong_long(unsigned long long a, unsigned long long b, unsigned long long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_ulong_long(unsigned long long a, unsigned long long b, unsigned long long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_ulong_long(unsigned long long a, unsigned long long b, unsigned long long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_ulong_long(unsigned long long a, unsigned long long b, unsigned long long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_ulong_long(unsigned long long a, unsigned long long b, unsigned long long *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_u8(uint8_t a, uint8_t b, uint8_t *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_u8(uint8_t a, uint8_t b, uint8_t *result);
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_u8(uint8_t a, uint8_t b, uint8_t *result);
@ -309,6 +362,96 @@ GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_int(int a, int b)
}
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_long(long a, long b)
{
if (b > 0 && a > LONG_MAX - b) {
return GUF_MATH_CKD_OVERFLOW_POS;
} else if (b < 0 && a < LONG_MIN - b) {
return GUF_MATH_CKD_OVERFLOW_NEG;
} else {
return GUF_MATH_CKD_SUCCESS;
}
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_long(long a, long b)
{
if (b < 0 && a > LONG_MAX + b) {
return GUF_MATH_CKD_OVERFLOW_POS;
} else if (b > 0 && a < LONG_MIN + b) {
return GUF_MATH_CKD_OVERFLOW_NEG;
} else {
return GUF_MATH_CKD_SUCCESS;
}
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_long(long a, long b)
{
if (b > 0) {
if (a > LONG_MAX / b) {
return GUF_MATH_CKD_OVERFLOW_POS;
} else if (a < LONG_MIN / b) {
return GUF_MATH_CKD_OVERFLOW_NEG;
} else {
return GUF_MATH_CKD_SUCCESS;
}
} else if (b < 0) {
if (LONG_MIN != -LONG_MAX && b == -1) { // Prevent potential (LONG_MIN / b) overflow for b == -1
return a == LONG_MIN ? GUF_MATH_CKD_OVERFLOW_POS : GUF_MATH_CKD_SUCCESS;
} else if (a < LONG_MAX / b) {
return GUF_MATH_CKD_OVERFLOW_POS;
} else if (a > LONG_MIN / b) {
return GUF_MATH_CKD_OVERFLOW_NEG;
} else {
return GUF_MATH_CKD_SUCCESS;
}
} else {
return GUF_MATH_CKD_SUCCESS;
}
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_long_long(long long a, long long b)
{
if (b > 0 && a > LLONG_MAX - b) {
return GUF_MATH_CKD_OVERFLOW_POS;
} else if (b < 0 && a < LLONG_MIN - b) {
return GUF_MATH_CKD_OVERFLOW_NEG;
} else {
return GUF_MATH_CKD_SUCCESS;
}
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_long_long(long long a, long long b)
{
if (b < 0 && a > LLONG_MAX + b) {
return GUF_MATH_CKD_OVERFLOW_POS;
} else if (b > 0 && a < LLONG_MIN + b) {
return GUF_MATH_CKD_OVERFLOW_NEG;
} else {
return GUF_MATH_CKD_SUCCESS;
}
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_long_long(long long a, long long b)
{
if (b > 0) {
if (a > LLONG_MAX / b) {
return GUF_MATH_CKD_OVERFLOW_POS;
} else if (a < LLONG_MIN / b) {
return GUF_MATH_CKD_OVERFLOW_NEG;
} else {
return GUF_MATH_CKD_SUCCESS;
}
} else if (b < 0) {
if (LLONG_MIN != -LLONG_MAX && b == -1) { // Prevent potential (LLONG_MIN / b) overflow for b == -1
return a == LLONG_MIN ? GUF_MATH_CKD_OVERFLOW_POS : GUF_MATH_CKD_SUCCESS;
} else if (a < LLONG_MAX / b) {
return GUF_MATH_CKD_OVERFLOW_POS;
} else if (a > LLONG_MIN / b) {
return GUF_MATH_CKD_OVERFLOW_NEG;
} else {
return GUF_MATH_CKD_SUCCESS;
}
} else {
return GUF_MATH_CKD_SUCCESS;
}
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_i8(int8_t a, int8_t b)
{
if (b > 0 && a > INT8_MAX - b) {
@ -580,6 +723,50 @@ GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_unsigned(unsigned a, unsig
return a != 0 && ((1u * c / a) != b) ? GUF_MATH_CKD_OVERFLOW_POS : GUF_MATH_CKD_SUCCESS;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_ulong(unsigned long a, unsigned long b)
{
if (b > 0 && a > ULONG_MAX - b) {
return GUF_MATH_CKD_OVERFLOW_POS;
} else {
return GUF_MATH_CKD_SUCCESS;
}
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_ulong(unsigned long a, unsigned long b)
{
if (b > a) {
return GUF_MATH_CKD_OVERFLOW_NEG;
} else {
return GUF_MATH_CKD_SUCCESS;
}
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_ulong(unsigned long a, unsigned long b)
{
const unsigned long c = 1u * a * b;
return a != 0 && ((1u * c / a) != b) ? GUF_MATH_CKD_OVERFLOW_POS : GUF_MATH_CKD_SUCCESS;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_ulong_long(unsigned long long a, unsigned long long b)
{
if (b > 0 && a > ULLONG_MAX - b) {
return GUF_MATH_CKD_OVERFLOW_POS;
} else {
return GUF_MATH_CKD_SUCCESS;
}
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_sub_ulong_long(unsigned long long a, unsigned long long b)
{
if (b > a) {
return GUF_MATH_CKD_OVERFLOW_NEG;
} else {
return GUF_MATH_CKD_SUCCESS;
}
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_mul_ulong_long(unsigned long long a, unsigned long long b)
{
const unsigned long long c = 1u * a * b;
return a != 0 && ((1u * c / a) != b) ? GUF_MATH_CKD_OVERFLOW_POS : GUF_MATH_CKD_SUCCESS;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_ckd_add_u8(uint8_t a, uint8_t b)
{
if (b > 0 && a > UINT8_MAX - b) {
@ -824,6 +1011,268 @@ GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_int(int a, int b, int
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_long(long a, long b, long *result)
{
const guf_math_ckd_result check = guf_ckd_add_long(a, b);
if (result) {
switch (check) {
case GUF_MATH_CKD_SUCCESS:
*result = a + b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
*result = LONG_MAX;
break;
case GUF_MATH_CKD_OVERFLOW_NEG:
*result = LONG_MIN;
break;
default:
GUF_ASSERT(false);
}
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_long(long a, long b, long *result)
{
const guf_math_ckd_result check = guf_ckd_sub_long(a, b);
if (result) {
switch (check) {
case GUF_MATH_CKD_SUCCESS:
*result = a - b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
*result = LONG_MAX;
break;
case GUF_MATH_CKD_OVERFLOW_NEG:
*result = LONG_MIN;
break;
default:
GUF_ASSERT(false);
}
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_long(long a, long b, long *result)
{
const guf_math_ckd_result check = guf_ckd_mul_long(a, b);
if (result) {
switch (check) {
case GUF_MATH_CKD_SUCCESS:
*result = a * b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
*result = LONG_MAX;
break;
case GUF_MATH_CKD_OVERFLOW_NEG:
*result = LONG_MIN;
break;
default:
GUF_ASSERT(false);
}
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_long(long a, long b, long *result)
{
const guf_math_ckd_result check = guf_ckd_add_long(a, b);
if (result) {
switch (check) {
case GUF_MATH_CKD_SUCCESS:
*result = a + b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
*result = (a + LONG_MIN) + (b + LONG_MIN);
break;
case GUF_MATH_CKD_OVERFLOW_NEG:
*result = (a - LONG_MIN) + (b - LONG_MIN);
break;
default:
GUF_ASSERT(false);
}
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_long(long a, long b, long *result)
{
const guf_math_ckd_result check = guf_ckd_sub_long(a, b);
if (result) {
switch (check) {
case GUF_MATH_CKD_SUCCESS:
*result = a - b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
GUF_ASSERT(b < 0);
*result = (a + LONG_MIN) - (b - LONG_MIN); // TODO: not sure
break;
case GUF_MATH_CKD_OVERFLOW_NEG:
GUF_ASSERT(b > 0);
*result = (a - LONG_MIN) - (b + LONG_MIN); // TODO: not sure
break;
default:
GUF_ASSERT(false);
}
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_long(long a, long b, long *result)
{
const guf_math_ckd_result check = guf_ckd_mul_long(a, b);
if (result) {
switch (check) {
case GUF_MATH_CKD_SUCCESS:
*result = a * b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
case GUF_MATH_CKD_OVERFLOW_NEG: {
unsigned long res = 1u * (unsigned long)a * (unsigned long)b;
if (res > LONG_MAX) { // This is the fix for implementation defined conversion from unsigned to signed.
const unsigned long mod = (1u + (unsigned long)LONG_MAX);
res = mod > 0 ? (1u * res % mod) : res;
*result = LONG_MIN + (long)res;
} else {
*result = (long)res;
}
break;
}
default:
GUF_ASSERT(false);
}
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_long_long(long long a, long long b, long long *result)
{
const guf_math_ckd_result check = guf_ckd_add_long_long(a, b);
if (result) {
switch (check) {
case GUF_MATH_CKD_SUCCESS:
*result = a + b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
*result = LLONG_MAX;
break;
case GUF_MATH_CKD_OVERFLOW_NEG:
*result = LLONG_MIN;
break;
default:
GUF_ASSERT(false);
}
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_long_long(long long a, long long b, long long *result)
{
const guf_math_ckd_result check = guf_ckd_sub_long_long(a, b);
if (result) {
switch (check) {
case GUF_MATH_CKD_SUCCESS:
*result = a - b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
*result = LLONG_MAX;
break;
case GUF_MATH_CKD_OVERFLOW_NEG:
*result = LLONG_MIN;
break;
default:
GUF_ASSERT(false);
}
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_long_long(long long a, long long b, long long *result)
{
const guf_math_ckd_result check = guf_ckd_mul_long_long(a, b);
if (result) {
switch (check) {
case GUF_MATH_CKD_SUCCESS:
*result = a * b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
*result = LLONG_MAX;
break;
case GUF_MATH_CKD_OVERFLOW_NEG:
*result = LLONG_MIN;
break;
default:
GUF_ASSERT(false);
}
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_long_long(long long a, long long b, long long *result)
{
const guf_math_ckd_result check = guf_ckd_add_long_long(a, b);
if (result) {
switch (check) {
case GUF_MATH_CKD_SUCCESS:
*result = a + b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
*result = (a + LLONG_MIN) + (b + LLONG_MIN);
break;
case GUF_MATH_CKD_OVERFLOW_NEG:
*result = (a - LLONG_MIN) + (b - LLONG_MIN);
break;
default:
GUF_ASSERT(false);
}
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_long_long(long long a, long long b, long long *result)
{
const guf_math_ckd_result check = guf_ckd_sub_long_long(a, b);
if (result) {
switch (check) {
case GUF_MATH_CKD_SUCCESS:
*result = a - b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
GUF_ASSERT(b < 0);
*result = (a + LLONG_MIN) - (b - LLONG_MIN); // TODO: not sure
break;
case GUF_MATH_CKD_OVERFLOW_NEG:
GUF_ASSERT(b > 0);
*result = (a - LLONG_MIN) - (b + LLONG_MIN); // TODO: not sure
break;
default:
GUF_ASSERT(false);
}
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_long_long(long long a, long long b, long long *result)
{
const guf_math_ckd_result check = guf_ckd_mul_long_long(a, b);
if (result) {
switch (check) {
case GUF_MATH_CKD_SUCCESS:
*result = a * b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
case GUF_MATH_CKD_OVERFLOW_NEG: {
unsigned long long res = 1u * (unsigned long long)a * (unsigned long long)b;
if (res > LLONG_MAX) { // This is the fix for implementation defined conversion from unsigned to signed.
const unsigned long long mod = (1u + (unsigned long long)LLONG_MAX);
res = mod > 0 ? (1u * res % mod) : res;
*result = LLONG_MIN + (long long)res;
} else {
*result = (long long)res;
}
break;
}
default:
GUF_ASSERT(false);
}
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_i8(int8_t a, int8_t b, int8_t *result)
{
const guf_math_ckd_result check = guf_ckd_add_i8(a, b);
@ -1643,6 +2092,168 @@ GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_unsigned(unsigned a,
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_ulong(unsigned long a, unsigned long b, unsigned long *result)
{
const guf_math_ckd_result check = guf_ckd_add_ulong(a, b);
GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW_POS);
if (result) {
switch (check) {
case GUF_MATH_CKD_SUCCESS:
*result = a + b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
*result = ULONG_MAX;
break;
default:
GUF_ASSERT(false);
}
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_ulong(unsigned long a, unsigned long b, unsigned long *result)
{
const guf_math_ckd_result check = guf_ckd_sub_ulong(a, b);
GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW_NEG);
if (result) {
switch (check) {
case GUF_MATH_CKD_SUCCESS:
*result = a - b;
break;
case GUF_MATH_CKD_OVERFLOW_NEG:
*result = 0;
break;
default:
GUF_ASSERT(false);
}
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_ulong(unsigned long a, unsigned long b, unsigned long *result)
{
const guf_math_ckd_result check = guf_ckd_mul_ulong(a, b);
GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW_POS);
if (result) {
switch (check) {
case GUF_MATH_CKD_SUCCESS:
*result = a * b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
*result = ULONG_MAX;
break;
default:
GUF_ASSERT(false);
}
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_ulong(unsigned long a, unsigned long b, unsigned long *result)
{
const guf_math_ckd_result check = guf_ckd_add_ulong(a, b);
if (result) {
*result = 1u * a + b;
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_ulong(unsigned long a, unsigned long b, unsigned long *result)
{
const guf_math_ckd_result check = guf_ckd_sub_ulong(a, b);
if (result) {
*result = 1u * a - b;
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_ulong(unsigned long a, unsigned long b, unsigned long *result)
{
const guf_math_ckd_result check = guf_ckd_mul_ulong(a, b);
if (result) {
*result = 1u * a * b;
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_ulong_long(unsigned long long a, unsigned long long b, unsigned long long *result)
{
const guf_math_ckd_result check = guf_ckd_add_ulong_long(a, b);
GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW_POS);
if (result) {
switch (check) {
case GUF_MATH_CKD_SUCCESS:
*result = a + b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
*result = ULLONG_MAX;
break;
default:
GUF_ASSERT(false);
}
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_sub_ulong_long(unsigned long long a, unsigned long long b, unsigned long long *result)
{
const guf_math_ckd_result check = guf_ckd_sub_ulong_long(a, b);
GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW_NEG);
if (result) {
switch (check) {
case GUF_MATH_CKD_SUCCESS:
*result = a - b;
break;
case GUF_MATH_CKD_OVERFLOW_NEG:
*result = 0;
break;
default:
GUF_ASSERT(false);
}
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_mul_ulong_long(unsigned long long a, unsigned long long b, unsigned long long *result)
{
const guf_math_ckd_result check = guf_ckd_mul_ulong_long(a, b);
GUF_ASSERT(check == GUF_MATH_CKD_SUCCESS || check == GUF_MATH_CKD_OVERFLOW_POS);
if (result) {
switch (check) {
case GUF_MATH_CKD_SUCCESS:
*result = a * b;
break;
case GUF_MATH_CKD_OVERFLOW_POS:
*result = ULLONG_MAX;
break;
default:
GUF_ASSERT(false);
}
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_add_ulong_long(unsigned long long a, unsigned long long b, unsigned long long *result)
{
const guf_math_ckd_result check = guf_ckd_add_ulong_long(a, b);
if (result) {
*result = 1u * a + b;
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_sub_ulong_long(unsigned long long a, unsigned long long b, unsigned long long *result)
{
const guf_math_ckd_result check = guf_ckd_sub_ulong_long(a, b);
if (result) {
*result = 1u * a - b;
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_wrapping_mul_ulong_long(unsigned long long a, unsigned long long b, unsigned long long *result)
{
const guf_math_ckd_result check = guf_ckd_mul_ulong_long(a, b);
if (result) {
*result = 1u * a * b;
}
return check;
}
GUF_MATH_CKDINT_KWRDS guf_math_ckd_result guf_saturating_add_u8(uint8_t a, uint8_t b, uint8_t *result)
{
const guf_math_ckd_result check = guf_ckd_add_u8(a, b);

View File

@ -82,6 +82,8 @@ typedef struct guf_str_tok_state {
// 1.) guf_str_view:
GUF_STR_KWRDS guf_str_view guf_str_view_from_str(const guf_str* str);
// Return a new guf_str_view corresponding to the substring in range [pos, pos + count) of str
GUF_STR_KWRDS guf_str_view guf_str_view_substr(guf_str_view str, ptrdiff_t pos, ptrdiff_t count);
@ -889,9 +891,10 @@ GUF_STR_KWRDS guf_str *guf_str_copy(guf_str *dst, const guf_str *src, void *ctx)
guf_str_init_empty(dst, src->allocator);
GUF_ASSERT(guf_str_is_short_internal_(dst));
char *dst_cstr = NULL;
if (!guf_str_is_short_internal_(src)) {
const size_t src_cap_with_null = guf_str_cap_internal_(src) + 1;
char *dst_cstr = src->allocator->alloc(src_cap_with_null, src->allocator->ctx);
dst_cstr = src->allocator->alloc(src_cap_with_null, src->allocator->ctx);
if (!dst_cstr) {
*dst = guf_str_new_uninitialised();
return NULL;
@ -901,15 +904,16 @@ GUF_STR_KWRDS guf_str *guf_str_copy(guf_str *dst, const guf_str *src, void *ctx)
dst->data.lng.size = src->data.lng.size;
} else {
dst->data.shrt.size = src->data.shrt.size;
dst_cstr = dst->data.shrt.c_str;
}
GUF_ASSERT(dst_cstr);
const size_t src_len_with_null = guf_str_len_internal_(src) + 1;
GUF_ASSERT(src_len_with_null == (guf_str_len_internal_(dst) + 1));
GUF_ASSERT(guf_str_is_short(dst) == guf_str_is_short(src));
GUF_ASSERT(guf_str_is_short_internal_(dst) == guf_str_is_short_internal_(src));
const char *src_cstr = guf_str_const_cstr(src);
char *dst_cstr = guf_str_cstr(dst);
GUF_ASSERT(src_cstr && dst_cstr);
GUF_ASSERT(src_cstr);
memcpy(dst_cstr, src_cstr, src_len_with_null);
GUF_ASSERT(guf_str_is_valid(dst));
@ -1205,6 +1209,8 @@ GUF_STR_KWRDS uint32_t guf_str_hash32(const guf_str *str)
}
// guf_str_view:
GUF_STR_KWRDS bool guf_str_view_is_valid(guf_str_view sv)
@ -1216,6 +1222,15 @@ GUF_STR_KWRDS bool guf_str_view_is_valid(guf_str_view sv)
}
}
GUF_STR_KWRDS guf_str_view guf_str_view_from_str(const guf_str *str)
{
GUF_ASSERT(str);
GUF_ASSERT(guf_str_is_valid(str));
return (guf_str_view){.str = guf_str_const_cstr(str), .len = guf_str_len(str)};
}
/*
cf. "str_pop_first_split":
- https://accu.org/conf-docs/PDFs_2021/luca_sass_modern_c_and_what_we_can_learn_from_it.pdf ("String handling in Modern C", page 128 of the pdf)

View File

@ -44,3 +44,12 @@
#define GUF_T_EQ guf_str_view_equal
#define GUF_DBUF_IMPL
#include "guf_dbuf.h"
#define GUF_T guf_str
#define GUF_DBUF_NAME dbuf_str
#define GUF_T_COPY guf_str_copy
#define GUF_T_MOVE guf_str_move
#define GUF_T_FREE guf_str_free
#define GUF_T_EQ guf_str_equal
#define GUF_DBUF_IMPL
#include "guf_dbuf.h"

View File

@ -42,4 +42,12 @@
#define GUF_T_EQ guf_str_view_equal
#include "guf_dbuf.h"
#define GUF_T guf_str
#define GUF_DBUF_NAME dbuf_str
#define GUF_T_COPY guf_str_copy
#define GUF_T_MOVE guf_str_move
#define GUF_T_FREE guf_str_free
#define GUF_T_EQ guf_str_equal
#include "guf_dbuf.h"
#endif

View File

@ -21,6 +21,8 @@ static void init_tests()
{
g_tests.push_back(std::make_unique<DbufIntTest>("DbufIntTest"));
g_tests.push_back(std::make_unique<DbufCstringTest>("DbufCstringTest"));
g_tests.push_back(std::make_unique<DbufStrTest>("DbufStrTest"));
g_tests.push_back(std::make_unique<DictSvToIntTest>("DictSvToIntTest"));
g_tests.push_back(std::make_unique<UTF8Test>("UTF8Test"));
g_tests.push_back(std::make_unique<StrTest>("StrTest"));

View File

@ -221,6 +221,8 @@ void DbufIntTest::test_insert_remove(int n)
}
/*
DbufCstringTest
*/
@ -539,3 +541,86 @@ void DbufCstringTest::test_find(int n)
dbuf_heap_cstr_free(&str_dbuf, NULL);
}
/*
DbufStrTest:
*/
void DbufStrTest::run()
{
test_push_insert_erase(16);
}
void DbufStrTest::test_push_insert_erase(size_t n, ptrdiff_t start_cap)
{
dbuf_str strings = start_cap < 0 ? dbuf_str_new(&allocator) : dbuf_str_new_with_capacity(start_cap, &allocator);
std::vector<std::string> strings_cpp {};
guf_libc_alloc_ctx str_allocator_ctx = {
.tracker = guf_alloc_tracker_new(42, "test_push_insert_erase: local str allocator", NULL, NULL),
.zero_init = false
};
guf_allocator str_allocator = guf_libc_allocator_new(&str_allocator_ctx);
for (size_t i = 0; i < n; ++i) {
std::string str;
for (size_t c = 0; c < 512 + GUF_STR_SSO_BUF_CAP; ++c) {
str += c % 10 + '0';
}
const guf_str_view sv_long = guf_str_view{.str = str.data(), .len = (ptrdiff_t)str.size()};
const guf_str_view sv_short = guf_str_view{.str = str.data(), .len = (ptrdiff_t)GUF_STR_SSO_BUF_CAP - 1};
guf_str long_str = GUF_STR_UNINITIALISED_CPP, short_str = GUF_STR_UNINITIALISED_CPP;
guf_str_init(&long_str, sv_long, &str_allocator);
guf_str_init(&short_str, sv_short, &str_allocator);
TEST_CHECK(str_allocator_ctx.tracker.alloc_count == 1 + (i*3));
// Move
guf_err err;
dbuf_str_try_push(&strings, &long_str, GUF_CPY_MOVE, &err);
TEST_CHECK(err == GUF_ERR_NONE);
dbuf_str_try_push(&strings, &short_str, GUF_CPY_MOVE, &err);
TEST_CHECK(err == GUF_ERR_NONE);
TEST_CHECK(str_allocator_ctx.tracker.alloc_count == 1 + (i*3));
TEST_CHECK(guf_str_is_uninit(&long_str));
TEST_CHECK(guf_str_is_uninit(&short_str));
// Deep-copy
guf_str_init(&long_str, sv_long, &str_allocator);
guf_str_init(&short_str, sv_short, &str_allocator);
TEST_CHECK(str_allocator_ctx.tracker.alloc_count == 2 + (i*3));
dbuf_str_try_push(&strings, &long_str, GUF_CPY_DEEP, &err);
TEST_CHECK(err == GUF_ERR_NONE);
dbuf_str_try_push(&strings, &short_str, GUF_CPY_DEEP, &err);
TEST_CHECK(err == GUF_ERR_NONE);
TEST_CHECK(str_allocator_ctx.tracker.alloc_count == 3 + (i*3));
TEST_CHECK(guf_str_is_valid(&long_str) && guf_str_is_valid(&short_str));
TEST_CHECK(guf_str_view_equal_val_arg(guf_str_view_from_str(&long_str), sv_long));
TEST_CHECK(guf_str_view_equal_val_arg(guf_str_view_from_str(&short_str), sv_short));
guf_str_free(&long_str, NULL);
guf_str_free(&short_str, NULL);
TEST_CHECK(str_allocator_ctx.tracker.free_count == 1 + (i*1));
TEST_CHECK(str_allocator_ctx.tracker.alloc_count == 3 + (i*3));
}
TEST_CHECK(str_allocator_ctx.tracker.free_count == n);
TEST_CHECK(str_allocator_ctx.tracker.alloc_count == 3 * n);
dbuf_str_free(&strings, NULL);
TEST_CHECK(!guf_alloc_tracker_found_leak(&str_allocator_ctx.tracker));
}

View File

@ -48,3 +48,22 @@ private:
void test_push_insert_erase(int n, ptrdiff_t start_cap = 0);
void test_find(int n = 32);
};
struct DbufStrTest : public Test
{
DbufStrTest(std::string name) : Test(name)
{
allocator_ctx.zero_init = false;
guf_alloc_tracker_init(&allocator_ctx.tracker, 3, "DbufStrTest_allocator", NULL, NULL);
guf_libc_allocator_init(&allocator, &allocator_ctx);
}
void run() override;
private:
guf_allocator allocator;
guf_libc_alloc_ctx allocator_ctx;
void test_push_insert_erase(size_t n, ptrdiff_t start_cap = 0);
};

View File

@ -372,6 +372,9 @@ if __name__ == "__main__":
int_types = [
IntType(INT_TYPE = "int", INT_TYPE_ABBR = "int", INT_MIN = "INT_MIN", INT_MAX = "INT_MAX", UINT_TYPE = "unsigned"),
IntType(INT_TYPE = "long", INT_TYPE_ABBR = "long", INT_MIN = "LONG_MIN", INT_MAX = "LONG_MAX", UINT_TYPE = "unsigned long"),
IntType(INT_TYPE = "long long", INT_TYPE_ABBR = "long_long", INT_MIN = "LLONG_MIN", INT_MAX = "LLONG_MAX", UINT_TYPE = "unsigned long long"),
IntType(INT_TYPE = "int8_t", INT_TYPE_ABBR = "i8", INT_MIN = "INT8_MIN", INT_MAX = "INT8_MAX", UINT_TYPE = "uint8_t"),
IntType(INT_TYPE = "int16_t", INT_TYPE_ABBR = "i16", INT_MIN = "INT16_MIN", INT_MAX = "INT16_MAX", UINT_TYPE = "uint16_t"),
IntType(INT_TYPE = "int32_t", INT_TYPE_ABBR = "i32", INT_MIN = "INT32_MIN", INT_MAX = "INT32_MAX", UINT_TYPE = "uint32_t"),
@ -380,13 +383,16 @@ if __name__ == "__main__":
]
uint_types = [
UintType(INT_TYPE = "unsigned char", INT_TYPE_ABBR = "uchar", INT_MIN = "0", INT_MAX = "UCHAR_MAX"),
UintType(INT_TYPE = "unsigned", INT_TYPE_ABBR = "unsigned", INT_MIN = "0", INT_MAX = "UINT_MAX"),
UintType(INT_TYPE = "uint8_t", INT_TYPE_ABBR = "u8", INT_MIN = "0", INT_MAX = "UINT8_MAX"),
UintType(INT_TYPE = "uint16_t", INT_TYPE_ABBR = "u16", INT_MIN = "0", INT_MAX = "UINT16_MAX"),
UintType(INT_TYPE = "uint32_t", INT_TYPE_ABBR = "u32", INT_MIN = "0", INT_MAX = "UINT32_MAX"),
UintType(INT_TYPE = "uint64_t", INT_TYPE_ABBR = "u64", INT_MIN = "0", INT_MAX = "UINT64_MAX"),
UintType(INT_TYPE = "size_t", INT_TYPE_ABBR = "size_t", INT_MIN = "0", INT_MAX = "SIZE_MAX"),
UintType(INT_TYPE = "unsigned char", INT_TYPE_ABBR = "uchar", INT_MIN = "0", INT_MAX = "UCHAR_MAX"),
UintType(INT_TYPE = "unsigned", INT_TYPE_ABBR = "unsigned", INT_MIN = "0", INT_MAX = "UINT_MAX"),
UintType(INT_TYPE = "unsigned long", INT_TYPE_ABBR = "ulong", INT_MIN = "ULONG_MIN", INT_MAX = "ULONG_MAX"),
UintType(INT_TYPE = "unsigned long long", INT_TYPE_ABBR = "ulong_long", INT_MIN = "ULLONG_MIN", INT_MAX = "ULLONG_MAX"),
UintType(INT_TYPE = "uint8_t", INT_TYPE_ABBR = "u8", INT_MIN = "0", INT_MAX = "UINT8_MAX"),
UintType(INT_TYPE = "uint16_t", INT_TYPE_ABBR = "u16", INT_MIN = "0", INT_MAX = "UINT16_MAX"),
UintType(INT_TYPE = "uint32_t", INT_TYPE_ABBR = "u32", INT_MIN = "0", INT_MAX = "UINT32_MAX"),
UintType(INT_TYPE = "uint64_t", INT_TYPE_ABBR = "u64", INT_MIN = "0", INT_MAX = "UINT64_MAX"),
UintType(INT_TYPE = "size_t", INT_TYPE_ABBR = "size_t", INT_MIN = "0", INT_MAX = "SIZE_MAX"),
]
code_header, code_impl = generate_ckdint_functions(int_types = int_types, uint_types= uint_types)