Skip to content

Commit

Permalink
include: Implement N2867.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
dag-erling committed Sep 7, 2023
1 parent 12b1c1e commit e6615b1
Show file tree
Hide file tree
Showing 4 changed files with 151 additions and 1 deletion.
2 changes: 1 addition & 1 deletion include/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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 \
Expand Down
40 changes: 40 additions & 0 deletions include/stdckdint.h
Original file line number Diff line number Diff line change
@@ -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
4 changes: 4 additions & 0 deletions share/man/man3/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ MAN= arb.3 \
snl.3 \
stats.3 \
stdarg.3 \
stdckdint.3 \
sysexits.3 \
tgmath.3 \
timeradd.3 \
Expand Down Expand Up @@ -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 \
Expand Down
106 changes: 106 additions & 0 deletions share/man/man3/stdckdint.3
Original file line number Diff line number Diff line change
@@ -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 [email protected] .

0 comments on commit e6615b1

Please sign in to comment.