From e6615b10347caf67f5bc12c9a8e30b8ddd9860ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dag-Erling=20Sm=C3=B8rgrav?= Date: Thu, 7 Sep 2023 06:14:54 +0000 Subject: [PATCH] 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 --- include/Makefile | 2 +- include/stdckdint.h | 40 ++++++++++++++ share/man/man3/Makefile | 4 ++ share/man/man3/stdckdint.3 | 106 +++++++++++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 include/stdckdint.h create mode 100644 share/man/man3/stdckdint.3 diff --git a/include/Makefile b/include/Makefile index 1d7651216cf9..bc1cfd96dfc9 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 + +#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 +#include +#include + +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 .