diff options
author | Dag-Erling Smørgrav <des@FreeBSD.org> | 2023-09-07 06:14:54 +0000 |
---|---|---|
committer | Dag-Erling Smørgrav <des@FreeBSD.org> | 2023-09-07 20:28:31 +0000 |
commit | c3ae84bc2a57e380c6703d7cbbfb6b541bde6391 (patch) | |
tree | 8018e14bdd09e59840c2cf843b211f6ec7b41a46 | |
parent | 3c96ab9f1d2855e1a2a1660648ecef597678eaa3 (diff) | |
download | src-c3ae84bc2a57e380c6703d7cbbfb6b541bde6391.tar.gz src-c3ae84bc2a57e380c6703d7cbbfb6b541bde6391.zip |
include: Implement N2867.
This adds macros for checked addition, subtraction, and multiplication with semantics similar to the builtins gcc and clang have had for years.
Reviewed by: kib, emaste
Differential Revision: https://reviews.freebsd.org/D41734
(cherry picked from commit e6615b10347caf67f5bc12c9a8e30b8ddd9860ae)
include: Add tests for N2867.
Reviewed by: imp
Differential Revision: https://reviews.freebsd.org/D41735
(cherry picked from commit 4fbb9c43aa44d9145151bb5f77d302ba01fb7551)
less: We have <stdckdint.h> now.
Reviewed by: delphij
Differential Revision: https://reviews.freebsd.org/D41736
(cherry picked from commit cb8dd292c7ec53391dfa25847858dd7ef895f94e)
Approved by: re (gjb)
-rw-r--r-- | etc/mtree/BSD.tests.dist | 2 | ||||
-rw-r--r-- | include/Makefile | 2 | ||||
-rw-r--r-- | include/stdckdint.h | 40 | ||||
-rw-r--r-- | share/man/man3/Makefile | 4 | ||||
-rw-r--r-- | share/man/man3/stdckdint.3 | 106 | ||||
-rw-r--r-- | tests/Makefile | 1 | ||||
-rw-r--r-- | tests/include/Makefile | 7 | ||||
-rw-r--r-- | tests/include/stdckdint_test.c | 52 | ||||
-rw-r--r-- | usr.bin/less/defines.h | 2 |
9 files changed, 214 insertions, 2 deletions
diff --git a/etc/mtree/BSD.tests.dist b/etc/mtree/BSD.tests.dist index fb755b4001ac..04dc24d772c8 100644 --- a/etc/mtree/BSD.tests.dist +++ b/etc/mtree/BSD.tests.dist @@ -278,6 +278,8 @@ .. .. .. + include + .. lib atf libatf-c diff --git a/include/Makefile b/include/Makefile index f3c9230f6d40..d8cdbfed3663 100644 --- a/include/Makefile +++ b/include/Makefile @@ -30,7 +30,7 @@ INCS= a.out.h ar.h assert.h bitstring.h byteswap.h \ pthread_np.h pwd.h ranlib.h readpassphrase.h regex.h \ res_update.h resolv.h runetype.h sched.h \ search.h semaphore.h setjmp.h \ - signal.h spawn.h stab.h stdalign.h stdbool.h stddef.h \ + signal.h spawn.h stab.h stdalign.h stdbool.h stdckdint.h stddef.h \ stdnoreturn.h stdio.h stdlib.h string.h stringlist.h \ strings.h sysexits.h tar.h termios.h tgmath.h \ time.h timeconv.h timers.h ttyent.h \ diff --git a/include/stdckdint.h b/include/stdckdint.h new file mode 100644 index 000000000000..af3074dded89 --- /dev/null +++ b/include/stdckdint.h @@ -0,0 +1,40 @@ +/*- + * Copyright (c) 2023 Dag-Erling Smørgrav + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#ifndef __STDC_VERSION_STDCKDINT_H__ +#define __STDC_VERSION_STDCKDINT_H__ 202311L + +#include <sys/cdefs.h> + +#if __BSD_VISIBLE || __ISO_C_VISIBLE >= 2023 + +#if __GNUC_PREREQ__(5, 1) || __has_builtin(__builtin_add_overflow) +#define ckd_add(result, a, b) \ + (_Bool)__builtin_add_overflow((a), (b), (result)) +#else +#define ckd_add(result, a, b) \ + _Static_assert(0, "checked addition not supported") +#endif + +#if __GNUC_PREREQ__(5, 1) || __has_builtin(__builtin_sub_overflow) +#define ckd_sub(result, a, b) \ + (_Bool)__builtin_sub_overflow((a), (b), (result)) +#else +#define ckd_sub(result, a, b) \ + _Static_assert(0, "checked subtraction not supported") +#endif + +#if __GNUC_PREREQ__(5, 1) || __has_builtin(__builtin_mul_overflow) +#define ckd_mul(result, a, b) \ + (_Bool)__builtin_mul_overflow((a), (b), (result)) +#else +#define ckd_mul(result, a, b) \ + _Static_assert(0, "checked multiplication not supported") +#endif + +#endif + +#endif diff --git a/share/man/man3/Makefile b/share/man/man3/Makefile index 5aec58492b8f..7fff5eedd5fb 100644 --- a/share/man/man3/Makefile +++ b/share/man/man3/Makefile @@ -29,6 +29,7 @@ MAN= arb.3 \ snl.3 \ stats.3 \ stdarg.3 \ + stdckdint.3 \ sysexits.3 \ tgmath.3 \ timeradd.3 \ @@ -310,6 +311,9 @@ MLINKS+= stdarg.3 va_arg.3 \ stdarg.3 va_end.3 \ stdarg.3 varargs.3 \ stdarg.3 va_start.3 +MLINKS+= stdckdint.3 ckd_add.3 \ + stdckdint.3 ckd_sub.3 \ + stdckdint.3 ckd_mul.3 MLINKS+= timeradd.3 timerclear.3 \ timeradd.3 timercmp.3 \ timeradd.3 timerisset.3 \ diff --git a/share/man/man3/stdckdint.3 b/share/man/man3/stdckdint.3 new file mode 100644 index 000000000000..e3593472c08b --- /dev/null +++ b/share/man/man3/stdckdint.3 @@ -0,0 +1,106 @@ +.\"- +.\" Copyright (c) 2023 Dag-Erling Smørgrav +.\" +.\" SPDX-License-Identifier: BSD-2-Clause +.\" +.Dd September 5, 2023 +.Dt STDCKDINT 3 +.Os +.Sh NAME +.Nm stdckdint +.Nd checked integer arithmetic +.Sh SYNOPSIS +.In stdckdint.h +.Ft bool +.Fn ckd_add "type1 *result" "type2 a" "type3 b" +.Ft bool +.Fn ckd_sub "type1 *result" "type2 a" "type3 b" +.Ft bool +.Fn ckd_mul "type1 *result" "type2 a" "type3 b" +.Sh DESCRIPTION +The function-like macros +.Nm ckd_add , +.Nm ckd_sub , +and +.Nm ckd_mul +perform checked integer addition, subtraction, and multiplication, +respectively. +If the result of adding, subtracting, or multiplying +.Fa a +and +.Fa b +as if their respective types had infinite range fits in +.Ft type1 , +it is stored in the location pointed to by +.Fa result +and the macro evaluates to +.Dv false . +Otherwise, the macro evaluates to +.Dv true +and the contents of the location pointed to by +.Fa result +is the result of the operation wrapped to the range of +.Ft type1 . +.Sh RETURN VALUES +The +.Nm ckd_add , +.Nm ckd_sub , +and +.Nm ckd_mul +macros evaluate to +.Dv true +if the requested operation overflowed the result type and +.Dv false +otherwise. +.Sh EXAMPLES +.Bd -literal -offset indent +#include <assert.h> +#include <limits.h> +#include <stdckdint.h> + +int main(void) +{ + int result; + + assert(!ckd_add(&result, INT_MAX, 0)); + assert(result == INT_MAX); + assert(ckd_add(&result, INT_MAX, 1)); + assert(result == INT_MIN); + + assert(!ckd_sub(&result, INT_MIN, 0)); + assert(result == INT_MIN); + assert(ckd_sub(&result, INT_MIN, 1)); + assert(result == INT_MAX); + + assert(!ckd_mul(&result, INT_MAX / 2, 2)); + assert(result == INT_MAX - 1); + assert(ckd_mul(&result, INT_MAX / 2 + 1, 2)); + assert(result == INT_MIN); + + return 0; +} +.Ed +.\" .Sh STANDARDS +.\" The +.\" .Nm ckd_add , +.\" .Nm ckd_sub , +.\" and +.\" .Nm ckd_mul +.\" macros conform to +.\" .St -isoC-23 . +.Sh HISTORY +The +.Nm ckd_add , +.Nm ckd_sub , +and +.Nm ckd_mul +macros were first introduced in +.Fx 14.0 . +.Sh AUTHORS +The +.Nm ckd_add , +.Nm ckd_sub , +and +.Nm ckd_mul +macros and this manual page were written by +.An Dag-Erling Sm\(/orgrav Aq Mt des@FreeBSD.org . diff --git a/tests/Makefile b/tests/Makefile index bd20d063ca71..09c0fbc62a2e 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -9,6 +9,7 @@ KYUAFILE= yes SUBDIR+= etc SUBDIR+= examples +SUBDIR+= include SUBDIR+= sys SUBDIR+= atf_python diff --git a/tests/include/Makefile b/tests/include/Makefile new file mode 100644 index 000000000000..e98d08da1f2b --- /dev/null +++ b/tests/include/Makefile @@ -0,0 +1,7 @@ +.include <bsd.own.mk> + +TESTSDIR= ${TESTSBASE}/include + +ATF_TESTS_C+= stdckdint_test + +.include <bsd.test.mk> diff --git a/tests/include/stdckdint_test.c b/tests/include/stdckdint_test.c new file mode 100644 index 000000000000..89262bbd5500 --- /dev/null +++ b/tests/include/stdckdint_test.c @@ -0,0 +1,52 @@ +/*- + * Copyright (c) 2023 Dag-Erling Smørgrav + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include <limits.h> +#include <stdckdint.h> + +#include <atf-c.h> + +ATF_TC_WITHOUT_HEAD(ckd_add); +ATF_TC_BODY(ckd_add, tc) +{ + int result; + + ATF_CHECK(!ckd_add(&result, INT_MAX, 0)); + ATF_CHECK_EQ(INT_MAX, result); + ATF_CHECK(ckd_add(&result, INT_MAX, 1)); + ATF_CHECK_EQ(INT_MIN, result); +} + +ATF_TC_WITHOUT_HEAD(ckd_sub); +ATF_TC_BODY(ckd_sub, tc) +{ + int result; + + ATF_CHECK(!ckd_sub(&result, INT_MIN, 0)); + ATF_CHECK_EQ(INT_MIN, result); + ATF_CHECK(ckd_sub(&result, INT_MIN, 1)); + ATF_CHECK_EQ(INT_MAX, result); +} + +ATF_TC_WITHOUT_HEAD(ckd_mul); +ATF_TC_BODY(ckd_mul, tc) +{ + int result; + + ATF_CHECK(!ckd_mul(&result, INT_MAX / 2, 2)); + ATF_CHECK_EQ(INT_MAX - 1, result); + ATF_CHECK(ckd_mul(&result, INT_MAX / 2 + 1, 2)); + ATF_CHECK_EQ(INT_MIN, result); +} + +ATF_TP_ADD_TCS(tp) +{ + ATF_TP_ADD_TC(tp, ckd_add); + ATF_TP_ADD_TC(tp, ckd_sub); + ATF_TP_ADD_TC(tp, ckd_mul); + return (atf_no_error()); + +} diff --git a/usr.bin/less/defines.h b/usr.bin/less/defines.h index 018d98a48162..ed9c2603970c 100644 --- a/usr.bin/less/defines.h +++ b/usr.bin/less/defines.h @@ -327,7 +327,7 @@ #define HAVE_STAT_INO 1 /* Define to 1 if you have the <stdckdint.h> header file. */ -/* #undef HAVE_STDCKDINT_H */ +#define HAVE_STDCKDINT_H 1 /* Define to 1 if you have the <stdint.h> header file. */ #define HAVE_STDINT_H 1 |