mirror of
https://github.com/freebsd/freebsd-src.git
synced 2024-11-30 04:22:44 +00:00
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 commite6615b1034
) include: Add tests for N2867. Reviewed by: imp Differential Revision: https://reviews.freebsd.org/D41735 (cherry picked from commit4fbb9c43aa
) less: We have <stdckdint.h> now. Reviewed by: delphij Differential Revision: https://reviews.freebsd.org/D41736 (cherry picked from commitcb8dd292c7
) Approved by: re (gjb)
This commit is contained in:
parent
3c96ab9f1d
commit
c3ae84bc2a
@ -278,6 +278,8 @@
|
||||
..
|
||||
..
|
||||
..
|
||||
include
|
||||
..
|
||||
lib
|
||||
atf
|
||||
libatf-c
|
||||
|
@ -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 \
|
||||
|
40
include/stdckdint.h
Normal file
40
include/stdckdint.h
Normal file
@ -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
|
@ -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 \
|
||||
|
106
share/man/man3/stdckdint.3
Normal file
106
share/man/man3/stdckdint.3
Normal file
@ -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 .
|
@ -9,6 +9,7 @@ KYUAFILE= yes
|
||||
|
||||
SUBDIR+= etc
|
||||
SUBDIR+= examples
|
||||
SUBDIR+= include
|
||||
SUBDIR+= sys
|
||||
SUBDIR+= atf_python
|
||||
|
||||
|
7
tests/include/Makefile
Normal file
7
tests/include/Makefile
Normal file
@ -0,0 +1,7 @@
|
||||
.include <bsd.own.mk>
|
||||
|
||||
TESTSDIR= ${TESTSBASE}/include
|
||||
|
||||
ATF_TESTS_C+= stdckdint_test
|
||||
|
||||
.include <bsd.test.mk>
|
52
tests/include/stdckdint_test.c
Normal file
52
tests/include/stdckdint_test.c
Normal file
@ -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());
|
||||
|
||||
}
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user