diff options
| -rw-r--r-- | .gitignore | 16 | ||||
| -rw-r--r-- | LICENSE | 15 | ||||
| -rw-r--r-- | Makefile | 110 | ||||
| -rw-r--r-- | README | 48 | ||||
| -rw-r--r-- | common.h | 86 | ||||
| -rw-r--r-- | config.mk | 8 | ||||
| -rw-r--r-- | libabort.7 | 59 | ||||
| -rw-r--r-- | libabort.h | 233 | ||||
| -rw-r--r-- | libabort_saprintf.3 | 58 | ||||
| -rw-r--r-- | libabort_saprintf.c | 28 | ||||
| -rw-r--r-- | libabort_stpacat.3 | 61 | ||||
| -rw-r--r-- | libabort_stpacat.c | 30 | ||||
| -rw-r--r-- | libabort_stpacpy.3 | 56 | ||||
| -rw-r--r-- | libabort_stpacpy.c | 27 | ||||
| -rw-r--r-- | libabort_stracat.3 | 62 | ||||
| -rw-r--r-- | libabort_stracat.c | 33 | ||||
| -rw-r--r-- | libabort_stracpy.3 | 56 | ||||
| -rw-r--r-- | libabort_stracpy.c | 28 | ||||
| -rw-r--r-- | libabort_stralen.3 | 53 | ||||
| -rw-r--r-- | libabort_stralen.c | 34 | ||||
| -rw-r--r-- | libabort_vsaprintf.3 | 58 | ||||
| -rw-r--r-- | libabort_vsaprintf.c | 11 | ||||
| -rw-r--r-- | mk/linux.mk | 6 | ||||
| -rw-r--r-- | mk/macos.mk | 6 | ||||
| -rw-r--r-- | mk/windows.mk | 6 | ||||
| l--------- | saprintf.3libabort | 1 | ||||
| l--------- | stpacat.3libabort | 1 | ||||
| l--------- | stpacpy.3libabort | 1 | ||||
| l--------- | stracat.3libabort | 1 | ||||
| l--------- | stracpy.3libabort | 1 | ||||
| l--------- | stralen.3libabort | 1 | ||||
| l--------- | vsaprintf.3libabort | 1 |
32 files changed, 1195 insertions, 0 deletions
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 @@ -0,0 +1,15 @@ +ISC License + +© 2026 Mattias Andrée <m@maandree.se> + +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 @@ -0,0 +1,48 @@ +NAME + libabort - String functions that abort when getting out of bounds + +SYNOPSIS + #include <libabort.h> + + 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 <libabort.h> 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 <sys/prctl.h> +# endif +# include <sys/resource.h> +# include <sys/types.h> +# include <sys/wait.h> +# include <signal.h> +# include <string.h> +# include <unistd.h> + + +# 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 <libabort.h> +.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 <libabort.h> +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 <stdarg.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +#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 <libabort.h> + +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 <libabort.h> + +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 <libabort.h> + +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 <libabort.h> + +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 <libabort.h> + +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 <libabort.h> + +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 <libabort.h> + +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 |
