From 41d3081c4ac0a79a4ad292957ead84f8477eaa55 Mon Sep 17 00:00:00 2001 From: Sertonix Date: Sat, 11 Oct 2025 18:25:20 +0200 Subject: Add `swab` Make the overlap check pedantic only since some software seems to rely on glibc working when src and dest are the same. --- README.md | 1 + include/unistd.h | 26 ++++++++++++++++++++++++++ tests/Makefile | 4 ++++ tests/test_swab_dynamic_read.c | 18 ++++++++++++++++++ tests/test_swab_dynamic_write.c | 18 ++++++++++++++++++ tests/test_swab_overwrite_over.c | 17 +++++++++++++++++ tests/test_swab_overwrite_under.c | 17 +++++++++++++++++ tests/test_swab_static_read.c | 18 ++++++++++++++++++ tests/test_swab_static_write.c | 18 ++++++++++++++++++ 9 files changed, 137 insertions(+) create mode 100644 tests/test_swab_dynamic_read.c create mode 100644 tests/test_swab_dynamic_write.c create mode 100644 tests/test_swab_overwrite_over.c create mode 100644 tests/test_swab_overwrite_under.c create mode 100644 tests/test_swab_static_read.c create mode 100644 tests/test_swab_static_write.c diff --git a/README.md b/README.md index e187776..8f8824a 100644 --- a/README.md +++ b/README.md @@ -116,6 +116,7 @@ At this point, the program will safely and loudly crash. - `strncat` - `strncpy` - `strrchr` +- `swab` - `tmpfile` - `ttyname_r` - `umask` diff --git a/include/unistd.h b/include/unistd.h index f6d4e87..b91dc56 100644 --- a/include/unistd.h +++ b/include/unistd.h @@ -178,6 +178,32 @@ _FORTIFY_FN(readlinkat) ssize_t readlinkat(int __f, const char *__p, return __orig_readlinkat(__f, __p, __s, __n); } +#if defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) || defined(_BSD_SOURCE) +#undef swab + +__fh_access(read_only, 1, 3) +__fh_access(write_only, 2, 3) +#if __has_builtin(__builtin_swab) +__diagnose_as_builtin(__builtin_swab, 1, 2, 3) +#endif +_FORTIFY_FN(swab) void swab(const void *restrict _FORTIFY_POS0 __os, + void *restrict _FORTIFY_POS0 __od, ssize_t __n) +__error_if((__fh_bos(__od, 0) < __n), "'swab' called with `n` bigger than the size of `d`.") +{ + __fh_size_t __bs = __fh_bos(__os, 0); + __fh_size_t __bd = __fh_bos(__od, 0); + +#if defined FORTIFY_PEDANTIC_CHECKS + if (__n > 0 && __fh_overlap(__os, __n, __od, __n)) + __builtin_trap(); +#endif + if (__n > __bs || __n > __bd) + __builtin_trap(); + return __orig_swab(__os, __od, __n); +} + +#endif + __fh_access(write_only, 2, 3) #if __has_builtin(__builtin_ttyname_r) __diagnose_as_builtin(__builtin_ttyname_r, 1, 2, 3) diff --git a/tests/Makefile b/tests/Makefile index e9e52dc..b4ea242 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -126,6 +126,10 @@ RUNTIME_TARGETS= \ test_strncpy_static_write \ test_strrchr_dynamic_read \ test_strrchr_static_read \ + test_swab_dynamic_read \ + test_swab_dynamic_write \ + test_swab_overwrite_over \ + test_swab_static_read \ test_ttyname_r_dynamic \ test_ttyname_r_static \ test_umask \ diff --git a/tests/test_swab_dynamic_read.c b/tests/test_swab_dynamic_read.c new file mode 100644 index 0000000..402dc4e --- /dev/null +++ b/tests/test_swab_dynamic_read.c @@ -0,0 +1,18 @@ +#define _XOPEN_SOURCE + +#include "common.h" + +#include + +int main(int argc, char** argv) { + char buffer[12] = {0}; + swab("1234567890", buffer, sizeof(buffer) - 1); + puts(buffer); + + CHK_FAIL_START + swab("123456", buffer, argc); + CHK_FAIL_END + + puts(buffer); + return ret; +} diff --git a/tests/test_swab_dynamic_write.c b/tests/test_swab_dynamic_write.c new file mode 100644 index 0000000..21725b7 --- /dev/null +++ b/tests/test_swab_dynamic_write.c @@ -0,0 +1,18 @@ +#define _XOPEN_SOURCE + +#include "common.h" + +#include + +int main(int argc, char** argv) { + char buffer[8] = {0}; + swab("1234567890", buffer, sizeof(buffer) - 1); + puts(buffer); + + CHK_FAIL_START + swab("1234567890", buffer, argc); + CHK_FAIL_END + + puts(buffer); + return ret; +} diff --git a/tests/test_swab_overwrite_over.c b/tests/test_swab_overwrite_over.c new file mode 100644 index 0000000..997f6d1 --- /dev/null +++ b/tests/test_swab_overwrite_over.c @@ -0,0 +1,17 @@ +#define _XOPEN_SOURCE + +#include "common.h" + +#include + +int main(int argc, char** argv) { + char buffer[9] = {'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', '\0'}; + puts(buffer); + + CHK_FAIL_START + swab(buffer+1, buffer, 5); + CHK_FAIL_END + + puts(buffer); + return ret; +} diff --git a/tests/test_swab_overwrite_under.c b/tests/test_swab_overwrite_under.c new file mode 100644 index 0000000..1d69545 --- /dev/null +++ b/tests/test_swab_overwrite_under.c @@ -0,0 +1,17 @@ +#define _XOPEN_SOURCE + +#include "common.h" + +#include + +int main(int argc, char** argv) { + char buffer[9] = {'A', 'A', 'A', 'A', 'B', 'B', 'B', 'B', '\0'}; + puts(buffer); + + CHK_FAIL_START + swab(buffer-1, buffer, 5); + CHK_FAIL_END + + puts(buffer); + return ret; +} diff --git a/tests/test_swab_static_read.c b/tests/test_swab_static_read.c new file mode 100644 index 0000000..f7fffcb --- /dev/null +++ b/tests/test_swab_static_read.c @@ -0,0 +1,18 @@ +#define _XOPEN_SOURCE + +#include "common.h" + +#include + +int main(int argc, char** argv) { + char buffer[8] = {0}; + swab("123456", buffer, 4); + puts(buffer); + + CHK_FAIL_START + swab("123456", buffer, sizeof(buffer)); + CHK_FAIL_END + + puts(buffer); + return ret; +} diff --git a/tests/test_swab_static_write.c b/tests/test_swab_static_write.c new file mode 100644 index 0000000..b5a63c6 --- /dev/null +++ b/tests/test_swab_static_write.c @@ -0,0 +1,18 @@ +#define _XOPEN_SOURCE + +#include "common.h" + +#include + +int main(int argc, char** argv) { + char buffer[8] = {0}; + swab("1234567890", buffer, sizeof(buffer) - 1); + puts(buffer); + + CHK_FAIL_START + swab("1234567890", buffer, sizeof(buffer) + 1); + CHK_FAIL_END + + puts(buffer); + return ret; +} -- cgit v1.3