From 7c545b4b9c31dbfb2e8430aded030654a92e967a Mon Sep 17 00:00:00 2001 From: Mattias Andrée Date: Sat, 28 Feb 2026 19:17:45 +0100 Subject: First commit MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Mattias Andrée --- .gitignore | 16 ++++ LICENSE | 15 ++++ Makefile | 110 ++++++++++++++++++++++++ README | 48 +++++++++++ common.h | 86 +++++++++++++++++++ config.mk | 8 ++ libabort.7 | 59 +++++++++++++ libabort.h | 233 +++++++++++++++++++++++++++++++++++++++++++++++++++ libabort_saprintf.3 | 58 +++++++++++++ libabort_saprintf.c | 28 +++++++ libabort_stpacat.3 | 61 ++++++++++++++ libabort_stpacat.c | 30 +++++++ libabort_stpacpy.3 | 56 +++++++++++++ libabort_stpacpy.c | 27 ++++++ libabort_stracat.3 | 62 ++++++++++++++ libabort_stracat.c | 33 ++++++++ libabort_stracpy.3 | 56 +++++++++++++ libabort_stracpy.c | 28 +++++++ libabort_stralen.3 | 53 ++++++++++++ libabort_stralen.c | 34 ++++++++ libabort_vsaprintf.3 | 58 +++++++++++++ libabort_vsaprintf.c | 11 +++ mk/linux.mk | 6 ++ mk/macos.mk | 6 ++ mk/windows.mk | 6 ++ saprintf.3libabort | 1 + stpacat.3libabort | 1 + stpacpy.3libabort | 1 + stracat.3libabort | 1 + stracpy.3libabort | 1 + stralen.3libabort | 1 + vsaprintf.3libabort | 1 + 32 files changed, 1195 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 Makefile create mode 100644 README create mode 100644 common.h create mode 100644 config.mk create mode 100644 libabort.7 create mode 100644 libabort.h create mode 100644 libabort_saprintf.3 create mode 100644 libabort_saprintf.c create mode 100644 libabort_stpacat.3 create mode 100644 libabort_stpacat.c create mode 100644 libabort_stpacpy.3 create mode 100644 libabort_stpacpy.c create mode 100644 libabort_stracat.3 create mode 100644 libabort_stracat.c create mode 100644 libabort_stracpy.3 create mode 100644 libabort_stracpy.c create mode 100644 libabort_stralen.3 create mode 100644 libabort_stralen.c create mode 100644 libabort_vsaprintf.3 create mode 100644 libabort_vsaprintf.c create mode 100644 mk/linux.mk create mode 100644 mk/macos.mk create mode 100644 mk/windows.mk create mode 120000 saprintf.3libabort create mode 120000 stpacat.3libabort create mode 120000 stpacpy.3libabort create mode 120000 stracat.3libabort create mode 120000 stracpy.3libabort create mode 120000 stralen.3libabort create mode 120000 vsaprintf.3libabort diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bb11397 --- /dev/null +++ b/.gitignore @@ -0,0 +1,16 @@ +*\#* +*~ +*.o +*.a +*.t +*.lo +*.to +*.su +*.so +*.so.* +*.dll +*.dylib +*.gch +*.gcov +*.gcno +*.gcda diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..1634eae --- /dev/null +++ b/LICENSE @@ -0,0 +1,15 @@ +ISC License + +© 2026 Mattias Andrée + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF +OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..8619f7e --- /dev/null +++ b/Makefile @@ -0,0 +1,110 @@ +.POSIX: + +CONFIGFILE = config.mk +include $(CONFIGFILE) + +OS = linux +# Linux: linux +# Mac OS: macos +# Windows: windows +include mk/$(OS).mk + + +LIB_MAJOR = 1 +LIB_MINOR = 0 +LIB_VERSION = $(LIB_MAJOR).$(LIB_MINOR) +LIB_NAME = abort + + +OBJ =\ + libabort_stracpy.o\ + libabort_stpacpy.o\ + libabort_stracat.o\ + libabort_stralen.o\ + libabort_stpacat.o\ + libabort_saprintf.o\ + libabort_vsaprintf.o + +HDR =\ + libabort.h\ + common.h + +MAN3 = $(OBJ:.o=.3)\ + stracpy.3libabort\ + saprintf.3libabort\ + vsaprintf.3libabort\ + stpacpy.3libabort\ + stracat.3libabort\ + stralen.3libabort\ + stpacat.3libabort + +MAN7 = libabort.7 + +LOBJ = $(OBJ:.o=.lo) +TOBJ = $(OBJ:.o=.to) +TEST = $(OBJ:.o=.t) + +all: libabort.a libabort.$(LIBEXT) $(TEST) +$(OBJ): $(HDR) +$(TOBJ): $(HDR) +$(LOBJ): $(HDR) +$(TEST): libabort.a + +.c.o: + $(CC) -c -o $@ $< $(CFLAGS) $(CPPFLAGS) + +.c.lo: + $(CC) -fPIC -c -o $@ $< $(CFLAGS) $(CPPFLAGS) + +.c.to: + $(CC) -DTEST -c -o $@ $< $(CFLAGS) $(CPPFLAGS) + +.to.t: + $(CC) -o $@ $< libabort.a $(LDPPFLAGS) + +libabort.a: $(OBJ) + @rm -f -- $@ + $(AR) rc $@ $(OBJ) + $(AR) ts $@ > /dev/null + +libabort.$(LIBEXT): $(LOBJ) + $(CC) $(LIBFLAGS) -o $@ $(LOBJ) $(LDFLAGS) + +check: $(TEST) + @set -e;\ + for t in $(TEST); do\ + printf '%s\n' ./$$t;\ + $(CHECK_PREFIX) ./$$t;\ + done + +install: libabort.a libabort.$(LIBEXT) + mkdir -p -- "$(DESTDIR)$(PREFIX)/lib" + mkdir -p -- "$(DESTDIR)$(PREFIX)/include" + mkdir -p -- "$(DESTDIR)$(MANPREFIX)/man3" + mkdir -p -- "$(DESTDIR)$(MANPREFIX)/man7" + cp -- libabort.a "$(DESTDIR)$(PREFIX)/lib/" + cp -- libabort.$(LIBEXT) "$(DESTDIR)$(PREFIX)/lib/libabort.$(LIBMINOREXT)" + $(FIX_INSTALL_NAME) "$(DESTDIR)$(PREFIX)/lib/libabort.$(LIBMINOREXT)" + ln -sf -- libabort.$(LIBMINOREXT) "$(DESTDIR)$(PREFIX)/lib/libabort.$(LIBMAJOREXT)" + ln -sf -- libabort.$(LIBMAJOREXT) "$(DESTDIR)$(PREFIX)/lib/libabort.$(LIBEXT)" + cp -- libabort.h "$(DESTDIR)$(PREFIX)/include/" + cp -P -- $(MAN3) "$(DESTDIR)$(MANPREFIX)/man3/" + cp -P -- $(MAN7) "$(DESTDIR)$(MANPREFIX)/man7/" + +uninstall: + -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libabort.a" + -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libabort.$(LIBMAJOREXT)" + -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libabort.$(LIBMINOREXT)" + -rm -f -- "$(DESTDIR)$(PREFIX)/lib/libabort.$(LIBEXT)" + -rm -f -- "$(DESTDIR)$(PREFIX)/include/libabort.h" + -cd -- "$(DESTDIR)$(MANPREFIX)/man3/" && rm -f -- $(MAN3) + -cd -- "$(DESTDIR)$(MANPREFIX)/man7/" && rm -f -- $(MAN7) + +clean: + -rm -f -- *.o *.a *.lo *.su *.so *.so.* *.dll *.dylib *.to *.t + -rm -f -- *.gch *.gcov *.gcno *.gcda *.$(LIBEXT) + +.SUFFIXES: +.SUFFIXES: .lo .o .c .t .to + +.PHONY: all check install uninstall clean diff --git a/README b/README new file mode 100644 index 0000000..95bf2d7 --- /dev/null +++ b/README @@ -0,0 +1,48 @@ +NAME + libabort - String functions that abort when getting out of bounds + +SYNOPSIS + #include + + Link with -labort. + +DESCRIPTION + libabort provides string functions that call abort(3) rather than + silently truncating or read or write out of bounds. + + Each function is namespaced with the prefix libabort_, and shorthand + names are available without this prefix, however defining + LIBABORT_NO_SHORTHANDS before including will cause these + shorthands not to be defined. + + The following functions are provided: + + libabort_stracpy(3) + Copy a NUL terminated string into a fixed-size buffer. + Returns the written string. + + libabort_stpacpy(3) + Copy a NUL terminated string into a fixed-size buffer. + Returns the end of the written string. + + libabort_stracat(3) + Append a NUL terminated string to a NUL terminated string within + a fixed-size buffer. Returns the augmented string. + + libabort_stpacat(3) + Append a NUL terminated string to a NUL terminated string within + a fixed-size buffer. Returns the end of the augmented string. + + libabort_stralen(3) + Compute the length of string that is expected to be NUL + terminated. + + libabort_saprintf(3) + Format a string into a fixed-size buffer. + + libabort_vsaprintf(3) + Format a string into a fixed-size buffer using a va_list + argument list. + +SEE ALSO + None. diff --git a/common.h b/common.h new file mode 100644 index 0000000..3e34f3b --- /dev/null +++ b/common.h @@ -0,0 +1,86 @@ +/* See LICENSE file for copyright and license details. */ +#include "libabort.h" + +#if defined(__GNUC__) +# define CONST __attribute__((__const__)) +#else +# define CONST +#endif + +#ifdef TEST +# ifdef __linux__ +# include +# endif +# include +# include +# include +# include +# include +# include + + +# if defined(PR_SET_DUMPABLE) +# define INIT_TEST_ABORT()\ + do {\ + struct rlimit rl__;\ + rl__.rlim_cur = 0;\ + rl__.rlim_max = 0;\ + (void) setrlimit(RLIMIT_CORE, &rl__);\ + (void) prctl(PR_SET_DUMPABLE, 0);\ + EXPECT_ABORT(abort());\ + } while (0) +# else +# define INIT_TEST_ABORT()\ + do {\ + struct rlimit rl__;\ + rl__.rlim_cur = 0;\ + rl__.rlim_max = 0;\ + (void) setrlimit(RLIMIT_CORE, &rl__);\ + EXPECT_ABORT(abort());\ + } while (0) +# endif + +# define EXPECT__(EXPR, HOW, RETEXTRACT, RETEXPECT)\ + do {\ + pid_t pid__;\ + int status__;\ + pid__ = fork();\ + EXPECT(pid__ != -1);\ + if (pid__ == 0) {\ + (EXPR);\ + _exit(0);\ + }\ + EXPECT(waitpid(pid__, &status__, 0) == pid__);\ + EXPECT(HOW(status__));\ + EXPECT(RETEXTRACT(status__) == RETEXPECT);\ + } while (0) + +# define EXPECT_ABORT(EXPR)\ + do {\ + EXPECT__(EXPR, WIFSIGNALED, WTERMSIG, SIGABRT);\ + } while (0) + +# define EXPECT_NO_ABORT(EXPR)\ + do {\ + EXPECT__(EXPR, WIFEXITED, WEXITSTATUS, 0);\ + (EXPR);\ + } while (0) + +# define EXPECT(EXPR)\ + do {\ + if (!(EXPR)) {\ + fprintf(stderr, "Failure at %s:%d: %s\n", __FILE__, __LINE__, #EXPR);\ + exit(1);\ + }\ + } while (0) + +# define TESTED\ + CONST int\ + main(void)\ + {\ + return 0;\ + } + +extern volatile size_t test_size_t_discard; + +#endif diff --git a/config.mk b/config.mk new file mode 100644 index 0000000..f4adf12 --- /dev/null +++ b/config.mk @@ -0,0 +1,8 @@ +PREFIX = /usr +MANPREFIX = $(PREFIX)/share/man + +CC = c99 + +CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_XOPEN_SOURCE=700 -D_GNU_SOURCE +CFLAGS = +LDFLAGS = diff --git a/libabort.7 b/libabort.7 new file mode 100644 index 0000000..4686be3 --- /dev/null +++ b/libabort.7 @@ -0,0 +1,59 @@ +.TH LIBABORT 7 LIBABORT +.SH NAME +libabort \- String functions that abort when getting out of bounds + +.SH SYNOPSIS +.nf +#include +.fi +.PP +Link with +.IR -labort . + +.SH DESCRIPTION +The +.BR libabort +library provides string functions that call +.BR abort (3) +rather than silently truncating or read or write out of bounds. +.PP +Each function is namespaced with the prefix +.BR libabort_ , +and shorthand names are available without this prefix, +however defining +.BR LIBABORT_NO_SHORTHANDS +before including +.I +will cause these shorthands not to be defined. +.PP +The following functions are provided: +.TP +.BR libabort_stracpy (3) +Copy a NUL terminated string into a fixed-size buffer. +Returns the written string. +.TP +.BR libabort_stpacpy (3) +Copy a NUL terminated string into a fixed-size buffer. +Returns the end of the written string. +.TP +.BR libabort_stracat (3) +Append a NUL terminated string to a NUL terminated string within a +fixed-size buffer. Returns the augmented string. +.TP +.BR libabort_stpacat (3) +Append a NUL terminated string to a NUL terminated string within a +fixed-size buffer. Returns the end of the augmented string. +.TP +.BR libabort_stralen (3) +Compute the length of string that is expected to be NUL terminated. +.TP +.BR libabort_saprintf (3) +Format a string into a fixed-size buffer. +.TP +.BR libabort_vsaprintf (3) +Format a string into a fixed-size buffer using a +.I va_list +argument list. + +.SH SEE ALSO +None. diff --git a/libabort.h b/libabort.h new file mode 100644 index 0000000..333edb3 --- /dev/null +++ b/libabort.h @@ -0,0 +1,233 @@ +/* See LICENSE file for copyright and license details. */ +#ifndef LIBABORT_H +#define LIBABORT_H + +#include +#include +#include +#include +#include + + +#if defined(__GNUC__) +# if defined(__clang__) +# define LIBABORT_PRINTF__(FMT, ARGS) __attribute__((__format__(__printf__, FMT, ARGS))) +# else +# define LIBABORT_PRINTF__(FMT, ARGS) __attribute__((__format__(__gnu_printf__, FMT, ARGS))) +# endif +# define LIBABORT_NONNULL__(INDEX) __attribute__((__nonnull__(INDEX))) +# define LIBABORT_ALL_NONNULL__ __attribute__((__nonnull__)) +# define LIBABORT_PURE__ __attribute__((__pure__)) +#else +# define LIBABORT_PRINTF__(FMT, ARGS) +# define LIBABORT_NONNULL__(INDEX) +# define LIBABORT_ALL_NONNULL__ +# define LIBABORT_PURE__ +#endif + + +#ifndef LIBABORT_NO_SHORTHANDS +# ifndef stracpy +# define stracpy libabort_stracpy +# endif +# ifndef saprintf +# define saprintf libabort_saprintf +# endif +# ifndef vsaprintf +# define vsaprintf libabort_vsaprintf +# endif +# ifndef stpacpy +# define stpacpy libabort_stpacpy +# endif +# ifndef stracat +# define stracat libabort_stracat +# endif +# ifndef stralen +# define stralen libabort_stralen +# endif +# ifndef stpacat +# define stpacat libabort_stpacat +# endif +#endif + + +/** + * libabort_stracpy + * + * Copy a string like strncpy(3), but abort if truncation would occur + * + * @param dst The destination buffer + * @param src The source string + * @param size The size of `dst`, in bytes + * @return `dst` + */ +LIBABORT_ALL_NONNULL__ +inline char * +libabort_stracpy(char *dst, const char *src, size_t size) +{ + size_t i; + for (i = 0; i < size; i++) + if ((dst[i] = src[i]) == '\0') + return dst; + abort(); +} + + +/** + * libabort_stpacpy + * + * Copy a string like stpcpy(3), but abort if truncation would occur. + * + * @param dst The destination buffer + * @param src The source string + * @param size The size of `dst`, in bytes + * @return A pointer to the terminating NUL byte in `dst` + */ +LIBABORT_ALL_NONNULL__ +inline char * +libabort_stpacpy(char *dst, const char *src, size_t size) +{ + size_t i; + for (i = 0; i < size; i++) + if ((dst[i] = src[i]) == '\0') + return &dst[i]; + abort(); +} + + +/** + * libabort_stracat + * + * Concatenate strings like strcat(3), but abort if truncation would occur. + * + * @param dst The destination buffer (must contain a NUL-terminated string) + * @param src The source string + * @param size The size of `dst`, in bytes + * @return `dst` + */ +LIBABORT_ALL_NONNULL__ +inline char * +libabort_stracat(char *dst, const char *src, size_t size) +{ + size_t i, j; + for (i = 0; i < size; i++) + if (dst[i] == '\0') + break; + if (i == size) + abort(); + for (j = 0; i < size; i++, j++) + if ((dst[i] = src[j]) == '\0') + return dst; + abort(); +} + + +/** + * libabort_stralen + * + * Get the length of a string like strlen(3), but abort if no NUL byte is found + * within `size` bytes. + * + * @param str The string + * @param size The maximum number of bytes to examine + * @return The length of the string, excluding the terminating NUL byte + */ +LIBABORT_PURE__ +LIBABORT_ALL_NONNULL__ +inline size_t +libabort_stralen(const char *str, size_t size) +{ + size_t i; + for (i = 0; i < size; i++) + if (!str[i]) + return i; + abort(); +} + + +/** + * libabort_stpacat + * + * Concatenate strings like stpcat(3) would (non-standard), but abort if + * truncation would occur. + * + * @param dst The destination buffer (must contain a NUL-terminated string) + * @param src The source string + * @param size The size of `dst`, in bytes + * @return A pointer to the terminating NUL byte in `dst` + */ +LIBABORT_ALL_NONNULL__ +inline char * +libabort_stpacat(char *dst, const char *src, size_t size) +{ + size_t i, j; + for (i = 0; i < size; i++) + if (dst[i] == '\0') + break; + if (i == size) + abort(); + for (j = 0; i < size; i++, j++) + if ((dst[i] = src[j]) == '\0') + return &dst[i]; + abort(); +} + + +/** + * libabort_vsaprintf + * + * Format a string like vsnprintf(3), but abort if truncation would occur + * + * @param buf The output buffer + * @param size The size of `buf`, in bytes + * @param fmt The format string + * @param ap The format arguments + * @return The number of bytes written excluding the terminating NUL byte + * + * NB! This function aborts if `size` is 0, use vsnprintf(3) get the size required for `buf` + */ +LIBABORT_NONNULL__(1) +LIBABORT_NONNULL__(3) +LIBABORT_PRINTF__(3, 0) +inline int +libabort_vsaprintf(char *buf, size_t size, const char *fmt, va_list ap) +{ + int n = vsnprintf(buf, size, fmt, ap); + if (n < 0 || (size_t)n >= size) + abort(); + return n; +} + + +/** + * libabort_saprintf + * + * Format a string like snprintf(3), but abort if truncation would occur + * + * @param buf The output buffer + * @param size The size of `buf`, in bytes + * @param fmt The format string + * @return The number of bytes written excluding the terminating NUL byte + * + * NB! This function aborts if `size` is 0, use snprintf(3) get the size required for `buf` + */ +LIBABORT_NONNULL__(1) +LIBABORT_NONNULL__(3) +LIBABORT_PRINTF__(3, 4) +inline int +libabort_saprintf(char *buf, size_t size, const char *fmt, ...) +{ + va_list ap; + int r; + va_start(ap, fmt); + r = libabort_vsaprintf(buf, size, fmt, ap); + va_end(ap); + return r; +} + + +#undef LIBABORT_PRINTF__ +#undef LIBABORT_NONNULL__ +#undef LIBABORT_ALL_NONNULL__ + +#endif diff --git a/libabort_saprintf.3 b/libabort_saprintf.3 new file mode 100644 index 0000000..559d06f --- /dev/null +++ b/libabort_saprintf.3 @@ -0,0 +1,58 @@ +.TH LIBABORT_SAPRINTF 3 LIBABORT +.SH NAME +libabort_saprintf \- Format a string with bounds checking + +.SH SYNOPSIS +.nf +#include + +int \fBlibabort_saprintf\fP(char *\fIbuf\fP, size_t \fIsize\fP, const char *\fIfmt\fP, ...); + +#if !defined(LIBABORT_NO_SHORTHANDS) && !defined(saprintf) +# define \fBsaprintf\fP libabort_saprintf +#endif +.fi +.PP +Link with +.IR -labort . + +.SH DESCRIPTION +The +.BR libabort_saprintf () +function formats a string according to +.I fmt +into the buffer +.IR buf , +which is assumed to be +.I size +bytes long. +.PP +If the formatted output does not fit in the destination buffer +(including the terminating NUL byte), or if +.I size +is zero, the +.BR libabort_saprintf () +function calls +.BR abort (3). + +.SH RETURN VALUE +The +.BR libabort_saprintf () +function returns the number of bytes written to +.IR buf , +excluding the terminating NUL byte. + +.SH ERRORS +The +.BR libabort_saprintf () +function cannot fail. + +.SH HISTORY +The +.BR libabort_saprintf () +function added in version 1.0 of +.BR libabort . + +.SH SEE ALSO +.BR libabort (7), +.BR libabort_vsaprintf (3) diff --git a/libabort_saprintf.c b/libabort_saprintf.c new file mode 100644 index 0000000..4468b91 --- /dev/null +++ b/libabort_saprintf.c @@ -0,0 +1,28 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libabort_saprintf(char *str, size_t size, const char *fmt, ...); + +#else + +int +main(void) +{ + char buf[6]; + int r; + + INIT_TEST_ABORT(); + + EXPECT_NO_ABORT(r = libabort_saprintf(buf, sizeof(buf), "%s", "hello")); + EXPECT(r == 5); + EXPECT(!buf[r]); + EXPECT(!strcmp(buf, "hello")); + + EXPECT_ABORT(libabort_saprintf(buf, sizeof(buf), "%s", "hello!")); + EXPECT_ABORT(libabort_saprintf(buf, 0, "%s", "")); + + return 0; +} + +#endif diff --git a/libabort_stpacat.3 b/libabort_stpacat.3 new file mode 100644 index 0000000..2efdc23 --- /dev/null +++ b/libabort_stpacat.3 @@ -0,0 +1,61 @@ +.TH LIBABORT_STPACAT 3 LIBABORT +.SH NAME +libabort_stpacat \- Append a string with bounds checking + +.SH SYNOPSIS +.nf +#include + +char *\fBlibabort_stpacat\fP(char *\fIdst\fP, const char *\fIsrc\fP, size_t \fIsize\fP); + +#if !defined(LIBABORT_NO_SHORTHANDS) && !defined(stpacat) +# define \fBstpacat\fP libabort_stpacat +#endif +.fi +.PP +Link with +.IR -labort . + +.SH DESCRIPTION +The +.BR libabort_stpacat () +function appends the NUL terminated string +.I src +to the NUL terminated string +.I dst +which is assumed to refer to a buffer of +.I size +bytes. +.PP +The function verifies that the concatenated +string fits in the destination buffer +(including the terminating NUL). If the +destination buffer is too small, or if +.I dst +is not NUL terminated within the first +.I size +bytes, the +.BR libabort_stpacat () +function calls +.BR abort (3). + +.SH RETURN VALUE +The +.BR libabort_stpacat () +function returns a pointer to the terminating NUL byte of the +resulting string. + +.SH ERRORS +The +.BR libabort_stpacat () +function cannot fail. + +.SH HISTORY +The +.BR libabort_stpacat () +function added in version 1.0 of +.BR libabort . + +.SH SEE ALSO +.BR libabort (7), +.BR libabort_stralen (3) diff --git a/libabort_stpacat.c b/libabort_stpacat.c new file mode 100644 index 0000000..35d8dd8 --- /dev/null +++ b/libabort_stpacat.c @@ -0,0 +1,30 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline char *libabort_stpacat(char *dst, const char *src, size_t size); + +#else + +int +main(void) +{ + char buf[32]; + char *p; + + INIT_TEST_ABORT(); + + stracpy(buf, "hello", sizeof(buf)); + EXPECT_NO_ABORT(p = stpacat(buf, " world", sizeof(buf))); + EXPECT(!strcmp(buf, "hello world")); + EXPECT(p == &buf[11]); + EXPECT(*p == '\0'); + + stracpy(buf, "hello", sizeof(buf)); + EXPECT_ABORT(stpacat(buf, " world", 11)); + EXPECT_ABORT(stpacat(buf, "", 0)); + + return 0; +} + +#endif diff --git a/libabort_stpacpy.3 b/libabort_stpacpy.3 new file mode 100644 index 0000000..3de9ea1 --- /dev/null +++ b/libabort_stpacpy.3 @@ -0,0 +1,56 @@ +.TH LIBABORT_STPACPY 3 LIBABORT +.SH NAME +libabort_stpacpy \- Copy a string with bounds checking + +.SH SYNOPSIS +.nf +#include + +char *\fBlibabort_stpacpy\fP(char *\fIdst\fP, const char *\fIsrc\fP, size_t \fIsize\fP); + +#if !defined(LIBABORT_NO_SHORTHANDS) && !defined(stpacpy) +# define \fBstpacpy\fP libabort_stpacpy +#endif +.fi +.PP +Link with +.IR -labort . + +.SH DESCRIPTION +The +.BR libabort_stpacpy () +function copies the NUL terminated string +.I src +into the buffer +.IR dst , +which is assumed to be +.I size +bytes long. +.PP +If the string does not fit in the destination buffer +(including the terminating NUL byte), the +.BR libabort_stpacpy () +function calls +.BR abort (3). + +.SH RETURN VALUE +The +.BR libabort_stpacpy () +function returns a pointer to the terminating NUL byte in +.IR dst . + +.SH ERRORS +The +.BR libabort_stpacpy () +function cannot fail. + +.SH HISTORY +The +.BR libabort_stpacpy () +function added in version 1.0 of +.BR libabort . + +.SH SEE ALSO +.BR libabort (7), +.BR libabort_stracpy (3), +.BR libabort_stpacat (3) diff --git a/libabort_stpacpy.c b/libabort_stpacpy.c new file mode 100644 index 0000000..5c48d65 --- /dev/null +++ b/libabort_stpacpy.c @@ -0,0 +1,27 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline char *libabort_stpacpy(char *dst, const char *src, size_t size); + +#else + +int +main(void) +{ + char buf[6]; + char *p; + + INIT_TEST_ABORT(); + + EXPECT_NO_ABORT(p = libabort_stpacpy(buf, "hello", sizeof(buf))); + EXPECT(p == &buf[5]); + EXPECT(!buf[5]); + EXPECT(!strcmp(buf, "hello")); + + EXPECT_ABORT(libabort_stpacpy(buf, "abcdef", sizeof(buf))); + + return 0; +} + +#endif diff --git a/libabort_stracat.3 b/libabort_stracat.3 new file mode 100644 index 0000000..16fe165 --- /dev/null +++ b/libabort_stracat.3 @@ -0,0 +1,62 @@ +.TH LIBABORT_STRACAT 3 LIBABORT +.SH NAME +libabort_stracat \- Append a string with bounds checking + +.SH SYNOPSIS +.nf +#include + +char *\fBlibabort_stracat\fP(char *\fIdst\fP, const char *\fIsrc\fP, size_t \fIsize\fP); + +#if !defined(LIBABORT_NO_SHORTHANDS) && !defined(stracat) +# define \fBstracat\fP libabort_stracat +#endif +.fi +.PP +Link with +.IR -labort . + +.SH DESCRIPTION +The +.BR libabort_stracat () +function appends the NUL terminated string +.I src +to the NUL terminated string +.I dst +in the buffer +.IR dst , +which is assumed to be +.I size +bytes long. +.PP +If the concatenated string does not fit in the destination buffer +(including the terminating NUL byte), or if +.I dst +is not NUL terminated within the first +.I size +bytes, the +.BR libabort_stracat () +function calls +.BR abort (3). + +.SH RETURN VALUE +The +.BR libabort_stracat () +function returns +.IR dst . + +.SH ERRORS +The +.BR libabort_stracat () +function cannot fail. + +.SH HISTORY +The +.BR libabort_stracat () +function added in version 1.0 of +.BR libabort . + +.SH SEE ALSO +.BR libabort (7), +.BR libabort_stpacat (3), +.BR libabort_stracpy (3) diff --git a/libabort_stracat.c b/libabort_stracat.c new file mode 100644 index 0000000..a3a32fb --- /dev/null +++ b/libabort_stracat.c @@ -0,0 +1,33 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline char *libabort_stracat(char *dst, const char *src, size_t size); + +#else + +int +main(void) +{ + char buf[16]; + char *p; + + INIT_TEST_ABORT(); + + buf[0] = '\0'; + EXPECT_NO_ABORT(p = libabort_stracat(buf, "hello", sizeof(buf))); + EXPECT(p == buf); + EXPECT(!buf[5]); + EXPECT(!strcmp(buf, "hello")); + + EXPECT_NO_ABORT(p = libabort_stracat(buf, " world", sizeof(buf))); + EXPECT(p == buf); + EXPECT(!buf[11]); + EXPECT(!strcmp(buf, "hello world")); + + EXPECT_ABORT(libabort_stracat(buf, " 0123456789abcdef", sizeof(buf))); + + return 0; +} + +#endif diff --git a/libabort_stracpy.3 b/libabort_stracpy.3 new file mode 100644 index 0000000..414fab1 --- /dev/null +++ b/libabort_stracpy.3 @@ -0,0 +1,56 @@ +.TH LIBABORT_STRACPY 3 LIBABORT +.SH NAME +libabort_stracpy \- Copy a string with bounds checking + +.SH SYNOPSIS +.nf +#include + +char *\fBlibabort_stracpy\fP(char *\fIdst\fP, const char *\fIsrc\fP, size_t \fIsize\fP); + +#if !defined(LIBABORT_NO_SHORTHANDS) && !defined(stracpy) +# define \fBstracpy\fP libabort_stracpy +#endif +.fi +.PP +Link with +.IR -labort . + +.SH DESCRIPTION +The +.BR libabort_stracpy () +function copies the NUL terminated string +.I src +into the buffer +.IR dst , +which is assumed to be +.I size +bytes long. +.PP +If the string does not fit in the destination buffer +(including the terminating NUL byte), the +.BR libabort_stracpy () +function calls +.BR abort (3). + +.SH RETURN VALUE +The +.BR libabort_stracpy () +function returns +.IR dst . + +.SH ERRORS +The +.BR libabort_stracpy () +function cannot fail. + +.SH HISTORY +The +.BR libabort_stracpy () +function added in version 1.0 of +.BR libabort . + +.SH SEE ALSO +.BR libabort (7), +.BR libabort_stpacpy (3), +.BR libabort_stracat (3) diff --git a/libabort_stracpy.c b/libabort_stracpy.c new file mode 100644 index 0000000..53541a8 --- /dev/null +++ b/libabort_stracpy.c @@ -0,0 +1,28 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline char *libabort_stracpy(char *dst, const char *src, size_t size); + +#else + +int +main(void) +{ + char buf[6]; + char *p; + + INIT_TEST_ABORT(); + + EXPECT_NO_ABORT(p = libabort_stracpy(buf, "hello", sizeof(buf))); + EXPECT(p == buf); + EXPECT(!buf[5]); + EXPECT(!strcmp(buf, "hello")); + + EXPECT_ABORT(libabort_stracpy(buf, "hello!", sizeof(buf))); + EXPECT_ABORT(libabort_stracpy(buf, "", 0)); + + return 0; +} + +#endif diff --git a/libabort_stralen.3 b/libabort_stralen.3 new file mode 100644 index 0000000..d2ef0d9 --- /dev/null +++ b/libabort_stralen.3 @@ -0,0 +1,53 @@ +.TH LIBABORT_STRALEN 3 LIBABORT +.SH NAME +libabort_stralen \- Get string length within a bounded size + +.SH SYNOPSIS +.nf +#include + +size_t \fBlibabort_stralen\fP(const char *\fIstr\fP, size_t \fIsize\fP); + +#if !defined(LIBABORT_NO_SHORTHANDS) && !defined(stralen) +# define \fBstralen\fP libabort_stralen +#endif +.fi + +.SH DESCRIPTION +The +.BR libabort_stralen () +function returns the length of the NUL terminated string +.I str +but will not read more than +.I size +bytes. +.PP +If no NUL terminator is found within the first +.I size +bytes, or if +.I size +is zero, the +.BR libabort_stralen () +function calls +.BR abort (3). + +.SH RETURN VALUE +The +.BR libabort_stralen () +function returns the length of +.IR str . + +.SH ERRORS +The +.BR libabort_stralen () +function cannot fail. + +.SH HISTORY +The +.BR libabort_stralen () +function added in version 1.0 of +.BR libabort . + +.SH SEE ALSO +.BR libabort (7), +.BR libabort_stpacat (3) diff --git a/libabort_stralen.c b/libabort_stralen.c new file mode 100644 index 0000000..8985256 --- /dev/null +++ b/libabort_stralen.c @@ -0,0 +1,34 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline size_t libabort_stralen(const char *str, size_t size); + +#else + +volatile size_t test_size_t_discard; + +int +main(void) +{ + size_t r; + + INIT_TEST_ABORT(); + + EXPECT_NO_ABORT(r = libabort_stralen("", 1)); + EXPECT(r == 0); + + EXPECT_NO_ABORT(r = libabort_stralen("hello", 6)); + EXPECT(r == 5); + + EXPECT_NO_ABORT(r = libabort_stralen("hello", 10)); + EXPECT(r == 5); + + EXPECT_ABORT(test_size_t_discard = libabort_stralen("hello", 4)); + EXPECT_ABORT(test_size_t_discard = libabort_stralen("hello", 5)); + EXPECT_ABORT(test_size_t_discard = libabort_stralen("", 0)); + + return 0; +} + +#endif diff --git a/libabort_vsaprintf.3 b/libabort_vsaprintf.3 new file mode 100644 index 0000000..8fbd385 --- /dev/null +++ b/libabort_vsaprintf.3 @@ -0,0 +1,58 @@ +.TH LIBABORT_VSAPRINTF 3 LIBABORT +.SH NAME +libabort_vsaprintf \- Format a string with bounds checking + +.SH SYNOPSIS +.nf +#include + +int \fBlibabort_vsaprintf\fP(char *\fIbuf\fP, size_t \fIsize\fP, const char *\fIfmt\fP, va_list \fIap\fP); + +#if !defined(LIBABORT_NO_SHORTHANDS) && !defined(vsaprintf) +# define \fBvsaprintf\fP libabort_vsaprintf +#endif +.fi +.PP +Link with +.IR -labort . + +.SH DESCRIPTION +The +.BR libabort_vsaprintf () +function formats a string according to +.I fmt +into the buffer +.IR buf , +which is assumed to be +.I size +bytes long. +.PP +If the formatted output does not fit in the destination buffer +(including the terminating NUL byte), or if +.I size +is zero, the +.BR libabort_vsaprintf () +function calls +.BR abort (3). + +.SH RETURN VALUE +The +.BR libabort_vsaprintf () +function returns the number of bytes written to +.IR buf , +excluding the terminating NUL byte. + +.SH ERRORS +The +.BR libabort_vsaprintf () +function cannot fail. + +.SH HISTORY +The +.BR libabort_vsaprintf () +function added in version 1.0 of +.BR libabort . + +.SH SEE ALSO +.BR libabort (7), +.BR libabort_saprintf (3) diff --git a/libabort_vsaprintf.c b/libabort_vsaprintf.c new file mode 100644 index 0000000..844e68f --- /dev/null +++ b/libabort_vsaprintf.c @@ -0,0 +1,11 @@ +/* See LICENSE file for copyright and license details. */ +#include "common.h" +#ifndef TEST + +extern inline int libabort_vsaprintf(char *str, size_t size, const char *fmt, va_list ap); + +#else + +TESTED /* via libabort_saprintf */ + +#endif diff --git a/mk/linux.mk b/mk/linux.mk new file mode 100644 index 0000000..ad58f69 --- /dev/null +++ b/mk/linux.mk @@ -0,0 +1,6 @@ +LIBEXT = so +LIBFLAGS = -shared -Wl,-soname,lib$(LIB_NAME).$(LIBEXT).$(LIB_MAJOR) +LIBMAJOREXT = $(LIBEXT).$(LIB_MAJOR) +LIBMINOREXT = $(LIBEXT).$(LIB_VERSION) + +FIX_INSTALL_NAME = : diff --git a/mk/macos.mk b/mk/macos.mk new file mode 100644 index 0000000..448f114 --- /dev/null +++ b/mk/macos.mk @@ -0,0 +1,6 @@ +LIBEXT = dylib +LIBFLAGS = -dynamiclib -Wl,-compatibility_version,$(LIB_MAJOR) -Wl,-current_version,$(LIB_VERSION) +LIBMAJOREXT = $(LIB_MAJOR).$(LIBEXT) +LIBMINOREXT = $(LIB_VERSION).$(LIBEXT) + +FIX_INSTALL_NAME = install_name_tool -id "$(PREFIX)/lib/libabort.$(LIBMAJOREXT)" diff --git a/mk/windows.mk b/mk/windows.mk new file mode 100644 index 0000000..ed5ec8d --- /dev/null +++ b/mk/windows.mk @@ -0,0 +1,6 @@ +LIBEXT = dll +LIBFLAGS = -shared +LIBMAJOREXT = $(LIB_MAJOR).$(LIBEXT) +LIBMINOREXT = $(LIB_VERSION).$(LIBEXT) + +FIX_INSTALL_NAME = : diff --git a/saprintf.3libabort b/saprintf.3libabort new file mode 120000 index 0000000..92177ad --- /dev/null +++ b/saprintf.3libabort @@ -0,0 +1 @@ +libabort_saprintf.3 \ No newline at end of file diff --git a/stpacat.3libabort b/stpacat.3libabort new file mode 120000 index 0000000..2da7a39 --- /dev/null +++ b/stpacat.3libabort @@ -0,0 +1 @@ +libabort_stpacat.3 \ No newline at end of file diff --git a/stpacpy.3libabort b/stpacpy.3libabort new file mode 120000 index 0000000..89d68dd --- /dev/null +++ b/stpacpy.3libabort @@ -0,0 +1 @@ +libabort_stpacpy.3 \ No newline at end of file diff --git a/stracat.3libabort b/stracat.3libabort new file mode 120000 index 0000000..2569712 --- /dev/null +++ b/stracat.3libabort @@ -0,0 +1 @@ +libabort_stracat.3 \ No newline at end of file diff --git a/stracpy.3libabort b/stracpy.3libabort new file mode 120000 index 0000000..a663685 --- /dev/null +++ b/stracpy.3libabort @@ -0,0 +1 @@ +libabort_stracpy.3 \ No newline at end of file diff --git a/stralen.3libabort b/stralen.3libabort new file mode 120000 index 0000000..b5987e6 --- /dev/null +++ b/stralen.3libabort @@ -0,0 +1 @@ +libabort_stralen.3 \ No newline at end of file diff --git a/vsaprintf.3libabort b/vsaprintf.3libabort new file mode 120000 index 0000000..51d57ba --- /dev/null +++ b/vsaprintf.3libabort @@ -0,0 +1 @@ +libabort_vsaprintf.3 \ No newline at end of file -- cgit v1.2.3-70-g09d2