lib/adds.[ch]: Add addsl() and addsl3()

These functions add 2 or 3 longs, saturating to LONG_{MIN,MAX} instead
of overflowing.

Cc: Tobias Stoeckmann <tobias@stoeckmann.org>
Signed-off-by: Alejandro Colomar <alx@kernel.org>
This commit is contained in:
Alejandro Colomar
2023-12-20 21:43:03 +01:00
committed by Serge Hallyn
parent 1a383194ff
commit 89e5a32966
3 changed files with 87 additions and 0 deletions

View File

@@ -23,6 +23,8 @@ libshadow_la_CFLAGS = $(LIBBSD_CFLAGS) $(LIBCRYPT_PAM) $(LIBSYSTEMD)
libshadow_la_SOURCES = \
addgrps.c \
adds.c \
adds.h \
age.c \
agetpass.c \
agetpass.h \

13
lib/adds.c Normal file
View File

@@ -0,0 +1,13 @@
// SPDX-FileCopyrightText: 2023, Alejandro Colomar <alx@kernel.org>
// SPDX-License-Identifier: BSD-3-Clause
#include <config.h>
#include "adds.h"
extern inline long addsl(long a, long b);
extern inline long addsl3(long a, long b, long c);
extern inline int cmpl(const void *p1, const void *p2);

72
lib/adds.h Normal file
View File

@@ -0,0 +1,72 @@
// SPDX-FileCopyrightText: 2023, Alejandro Colomar <alx@kernel.org>
// SPDX-License-Identifier: BSD-3-Clause
#ifndef SHADOW_INCLUDE_LIB_ADDS_H_
#define SHADOW_INCLUDE_LIB_ADDS_H_
#include <config.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include "sizeof.h"
inline long addsl(long a, long b);
inline long addsl3(long a, long b, long c);
inline int cmpl(const void *p1, const void *p2);
inline long
addsl(long a, long b)
{
if (a > 0 && b > LONG_MAX - a) {
errno = EOVERFLOW;
return LONG_MAX;
}
if (a < 0 && b < LONG_MIN - a) {
errno = EOVERFLOW;
return LONG_MIN;
}
return a + b;
}
inline long
addsl3(long a, long b, long c)
{
int e;
long sum;
long n[3] = {a, b, c};
e = errno;
qsort(n, NITEMS(n), sizeof(n[0]), cmpl);
errno = 0;
sum = addsl(n[0], n[2]);
if (errno == EOVERFLOW)
return sum;
errno = e;
return addsl(sum, n[1]);
}
inline int
cmpl(const void *p1, const void *p2)
{
const long *l1 = p1;
const long *l2 = p2;
if (*l1 < *l2)
return -1;
if (*l1 > *l2)
return +1;
return 0;
}
#endif // include guard