Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions examples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ add_subdirectory(matrix)
add_subdirectory(mpi)
add_subdirectory(notifier)
add_subdirectory(once)
add_subdirectory(overflow)
add_subdirectory(prandom)
add_subdirectory(radix)
add_subdirectory(ratelimit)
Expand Down
2 changes: 2 additions & 0 deletions examples/overflow/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-or-later
/overflow-simple
22 changes: 22 additions & 0 deletions examples/overflow/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Copyright(c) 2023 ffashion <helloworldffashion@gmail.com>
#

add_executable(overflow-simple simple.c)
target_link_libraries(overflow-simple bfdev)
add_test(overflow-simple overflow-simple)

if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev")
install(FILES
simple.c
DESTINATION
${CMAKE_INSTALL_DOCDIR}/examples/overflow
)

install(TARGETS
overflow-simple
DESTINATION
${CMAKE_INSTALL_DOCDIR}/bin
)
endif()
28 changes: 28 additions & 0 deletions examples/overflow/simple.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright(c) 2023 John Sanpe <sanpeqf@gmail.com>
*/

#define MODULE_NAME "overflow-simple"
#define bfdev_log_fmt(fmt) MODULE_NAME ": " fmt

#include <bfdev/log.h>
#include <bfdev/overflow.h>

int
main(int argc, const char *argv[])
{
bfdev_log_info("(signed char)127 + 1 = %d\n",
bfdev_overflow_add((signed char)127, 1));

bfdev_log_info("(unsigned char)255 + 1 = %d\n",
bfdev_overflow_add((unsigned char)255, 1));

bfdev_log_info("(signed char)-128 - 1 = %d\n",
bfdev_overflow_sub((signed char)-128, 1));

bfdev_log_info("(unsigned char)0 - 1 = %d\n",
bfdev_overflow_sub((unsigned char)0, 1));

return 0;
}
9 changes: 9 additions & 0 deletions include/bfdev/compiler.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ BFDEV_BEGIN_DECLS
#define bfdev_is_signed(type) (((type)(-1)) < (type)1)
#define bfdev_is_unsigned(type) (!bfdev_is_signed(type))

#define bfdev_type_half_max(type) \
((type)1 << (8 * sizeof(type) - 1 - bfdev_is_signed(type)))

#define bfdev_type_max(type) \
((type)((bfdev_type_half_max(type) - 1) + bfdev_type_half_max(type)))

#define bfdev_type_min(type) \
(((type)((type)-bfdev_type_max(type) - (type)1)))

/* Not-quite-unique ID. */
#ifndef __BFDEV_UNIQUE_ID
# define __BFDEV_UNIQUE_ID(prefix) __BFDEV_PASTE(__BFDEV_PASTE(__UNIQUE_ID_, prefix), __LINE__)
Expand Down
22 changes: 13 additions & 9 deletions include/bfdev/overflow.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <bfdev/config.h>
#include <bfdev/types.h>
#include <bfdev/stddef.h>
#include <bfdev/limits.h>

BFDEV_BEGIN_DECLS

Expand All @@ -18,7 +19,7 @@ BFDEV_BEGIN_DECLS
* @b: second addend.
* @d: pointer to store sum.
*
* Returns 0 on success.
* Returns true on wrap-around, false otherwise.
*/
#define bfdev_overflow_check_add(a, b, d) \
bfdev_overflow_check(({ \
Expand All @@ -36,7 +37,7 @@ bfdev_overflow_check(({ \
* @b: subtrahend; value to subtract from @a.
* @d: pointer to store difference.
*
* Returns 0 on success.
* Returns true on wrap-around, false otherwise.
*/
#define bfdev_overflow_check_sub(a, b, d) \
bfdev_overflow_check(({ \
Expand All @@ -54,7 +55,7 @@ bfdev_overflow_check(({ \
* @b: second factor.
* @d: pointer to store product.
*
* Returns 0 on success.
* Returns true on wrap-around, false otherwise.
*/
#define bfdev_overflow_check_mul(a, b, d) \
bfdev_overflow_check(({ \
Expand All @@ -71,23 +72,23 @@ bfdev_overflow_check(({ \
type __b = (type)(b); \
type __d; \
bfdev_overflow_check_add(__a, __b, &__d) \
? (type)~0ULL : __d; \
? bfdev_type_max(type) : __d; \
})

#define bfdev_overflow_sub_type(type, a, b) ({ \
type __a = (type)(a); \
type __b = (type)(b); \
type __d; \
bfdev_overflow_check_sub(__a, __b, &__d) \
? (type)~0ULL : __d; \
? bfdev_type_min(type) : __d; \
})

#define bfdev_overflow_mul_type(type, a, b) ({ \
type __a = (type)(a); \
type __b = (type)(b); \
type __d; \
bfdev_overflow_check_mul(__a, __b, &__d) \
? (type)~0ULL : __d; \
? bfdev_type_max(type) : __d; \
})

static inline __bfdev_must_check bfdev_bool
Expand All @@ -101,7 +102,8 @@ bfdev_overflow_check(bfdev_bool overflow)
* @a: first addend.
* @b: second addend.
*
* Returns (type)~0ULL on failed.
* Returns: calculate @a + @b, any overflow causing the
* return value to be bfdev_type_max(type).
*/
#define bfdev_overflow_add(a, b) \
bfdev_overflow_add_type(typeof(a), a, b)
Expand All @@ -111,7 +113,8 @@ bfdev_overflow_check(bfdev_bool overflow)
* @a: minuend; value to subtract from.
* @b: subtrahend; value to subtract from @a.
*
* Returns (type)~0ULL on failed.
* Returns: calculate @a - @b, any overflow causing the
* return value to be bfdev_type_min(type).
*/
#define bfdev_overflow_sub(a, b) \
bfdev_overflow_sub_type(typeof(a), a, b)
Expand All @@ -121,7 +124,8 @@ bfdev_overflow_check(bfdev_bool overflow)
* @a: first factor.
* @b: second factor.
*
* Returns (type)~0ULL on failed.
* Returns: calculate @a * @b, any overflow causing the
* return value to be bfdev_type_max(type).
*/
#define bfdev_overflow_mul(a, b) \
bfdev_overflow_mul_type(typeof(a), a, b)
Expand Down
1 change: 1 addition & 0 deletions testsuite/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ add_subdirectory(libc)
add_subdirectory(list)
add_subdirectory(memalloc)
add_subdirectory(mpi)
add_subdirectory(overflow)
add_subdirectory(slist)
2 changes: 2 additions & 0 deletions testsuite/overflow/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# SPDX-License-Identifier: GPL-2.0-or-later
/overflow-selftest
16 changes: 16 additions & 0 deletions testsuite/overflow/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# SPDX-License-Identifier: GPL-2.0-or-later
#
# Copyright(c) 2025 John Sanpe <sanpeqf@gmail.com>
#

add_executable(overflow-selftest selftest.c)
target_link_libraries(overflow-selftest bfdev testsuite)
add_test(overflow-selftest overflow-selftest)

if(${CMAKE_PROJECT_NAME} STREQUAL "bfdev")
install(TARGETS
overflow-selftest
DESTINATION
${CMAKE_INSTALL_DOCDIR}/testsuite
)
endif()
59 changes: 59 additions & 0 deletions testsuite/overflow/selftest.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright(c) 2023 John Sanpe <sanpeqf@gmail.com>
*/

#define MODULE_NAME "overflow-simple"
#define bfdev_log_fmt(fmt) MODULE_NAME ": " fmt

#include <stddef.h>
#include <limits.h>
#include <stdbool.h>
#include <bfdev/log.h>
#include <bfdev/overflow.h>
#include <testsuite.h>

#define TEST(calculate, limit) ({ \
bool cond; \
cond = bfdev_overflow_##calculate((limit), 1) == (limit); \
if (!cond) \
failed = true; \
cond ? "okay" : "failed"; \
})

TESTSUITE(
"overflow:selftest", NULL, NULL,
"overflow selftest"
) {
bool failed;

failed = false;
bfdev_log_info("add char: %s\n", TEST(add, (signed char)SCHAR_MAX));
bfdev_log_info("add short: %s\n", TEST(add, (signed short)SHRT_MAX));
bfdev_log_info("add int: %s\n", TEST(add, (signed int)INT_MAX));
bfdev_log_info("add long: %s\n", TEST(add, (signed long)LONG_MAX));
bfdev_log_info("add long long: %s\n", TEST(add, (signed long long)LLONG_MAX));

bfdev_log_info("add unsigned char: %s\n", TEST(add, (unsigned char)UCHAR_MAX));
bfdev_log_info("add unsigned short: %s\n", TEST(add, (unsigned short)USHRT_MAX));
bfdev_log_info("add unsigned int: %s\n", TEST(add, (unsigned int)UINT_MAX));
bfdev_log_info("add unsigned long: %s\n", TEST(add, (unsigned long)ULONG_MAX));
bfdev_log_info("add unsigned long long: %s\n", TEST(add, (unsigned long long)ULLONG_MAX));

bfdev_log_info("sub char: %s\n", TEST(sub, (signed char)SCHAR_MIN));
bfdev_log_info("sub short: %s\n", TEST(sub, (signed short)SHRT_MIN));
bfdev_log_info("sub int: %s\n", TEST(sub, (signed int)INT_MIN));
bfdev_log_info("sub long: %s\n", TEST(sub, (signed long)LONG_MIN));
bfdev_log_info("sub long long: %s\n", TEST(sub, (signed long long)LLONG_MIN));

bfdev_log_info("sub unsigned char: %s\n", TEST(sub, (unsigned char)0));
bfdev_log_info("sub unsigned short: %s\n", TEST(sub, (unsigned short)0));
bfdev_log_info("sub unsigned int: %s\n", TEST(sub, (unsigned int)0));
bfdev_log_info("sub unsigned long: %s\n", TEST(sub, (unsigned long)0));
bfdev_log_info("sub unsigned long long: %s\n", TEST(sub, (unsigned long long)0));

if (failed)
return -BFDEV_EFAULT;

return -BFDEV_ENOERR;
}
Loading