From e4e15ed286f7739682737ec2ca6d681dbdd00e79 Mon Sep 17 00:00:00 2001 From: Guillem Jover Date: Tue, 22 May 2018 13:50:44 +0200 Subject: [PATCH] Fix strnvis() and strnunvis() NetBSD ABI break The NetBSD implementations have different prototypes to the ones coming from OpenBSD, which will break builds, and have caused segfaults at run-time. We provide now both interfaces with different prototypes as different version nodes allow selecting them at compile-time, defaulting for now to the OpenBSD one to avoid build-time breakage, while emitting a compile-time warning. Later on, in 0.10.0, we will be switching the compile-time default to the NetBSD version. Ref: http://gnats.netbsd.org/44977 Fixes: https://bugs.debian.org/899282 --- include/bsd/vis.h | 34 +++++++++++++++++++++++++++++++-- src/libbsd.map | 8 ++++++++ src/unvis.c | 29 ++++++++++++++++++++++++++-- src/vis.c | 27 +++++++++++++++++++++++++- test/.gitignore | 2 ++ test/Makefile.am | 2 ++ test/vis-openbsd.c | 47 ++++++++++++++++++++++++++++++++++++++++++++++ test/vis.c | 46 +++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 190 insertions(+), 5 deletions(-) create mode 100644 test/vis-openbsd.c create mode 100644 test/vis.c diff --git a/include/bsd/vis.h b/include/bsd/vis.h index d8b6635..84102b2 100644 --- a/include/bsd/vis.h +++ b/include/bsd/vis.h @@ -88,6 +88,22 @@ #include #endif +/* + * NetBSD added an strnvis and unfortunately made it incompatible with the + * existing one in OpenBSD and Freedesktop's libbsd (the former having existed + * for over ten years). Despite this incompatibility being reported during + * development (see http://gnats.netbsd.org/44977) they still shipped it. + * Even more unfortunately FreeBSD and later MacOS picked up this incompatible + * implementation. + * + * Provide both implementations and default for now on the historical one to + * avoid breakage, we will switch to the NetBSD one in libbsd 0.10.0 or so. + * Define LIBBSD_NETBSD_VIS to switch to the NetBSD one now. + */ +#ifndef LIBBSD_NETBSD_VIS +#warning "NetBSD added incompatible strnvis() and strnunvis(), please see for more detils." +#endif + __BEGIN_DECLS char *vis(char *, int, int, int); char *nvis(char *, size_t, int, int, int); @@ -97,7 +113,14 @@ char *snvis(char *, size_t, int, int, int, const char *); int strvis(char *, const char *, int); int stravis(char **, const char *, int); -int strnvis(char *, size_t, const char *, int); +#ifdef LIBBSD_NETBSD_VIS +/* NetBSD prototype. */ +int LIBBSD_REDIRECT(strnvis, (char *, size_t, const char *, int), + strnvis_netbsd); +#else +/* OpenBSD prototype (current default). */ +int strnvis(char *, const char *, size_t, int); +#endif int strsvis(char *, const char *, int, const char *); int strsnvis(char *, size_t, const char *, int, const char *); @@ -112,7 +135,14 @@ int strsenvisx(char *, size_t, const char *, size_t , int, const char *, int *); int strunvis(char *, const char *); -int strnunvis(char *, size_t, const char *); +#ifdef LIBBSD_NETBSD_VIS +/* NetBSD prototype. */ +int LIBBSD_REDIRECT(strnunvis, (char *, size_t, const char *), + strnunvis_netbsd); +#else +/* OpenBSD prototype (current default). */ +ssize_t strnunvis(char *, const char *, size_t); +#endif int strunvisx(char *, const char *, int); int strnunvisx(char *, size_t, const char *, int); diff --git a/src/libbsd.map b/src/libbsd.map index 98b95ce..ce36040 100644 --- a/src/libbsd.map +++ b/src/libbsd.map @@ -160,3 +160,11 @@ LIBBSD_0.9 { strsvisx; svis; } LIBBSD_0.8; + +LIBBSD_0.9.1 { + /* The strnvis() and strnunvis() symbols changed prototype to match + * the NetBSD implementation. Provided as versioned nodes in 0.9.1, and + * exposed here explicitly so that we can redirect at compile-time. */ + strnvis_netbsd; + strnunvis_netbsd; +} LIBBSD_0.9; diff --git a/src/unvis.c b/src/unvis.c index e16bd50..94e3e7a 100644 --- a/src/unvis.c +++ b/src/unvis.c @@ -37,7 +37,10 @@ #include #include #include +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcpp" #include +#pragma GCC diagnostic pop #ifdef __weak_alias __weak_alias(strnunvisx,_strnunvisx) @@ -543,8 +546,30 @@ strunvis(char *dst, const char *src) return strnunvisx(dst, (size_t)~0, src, 0); } -int -strnunvis(char *dst, size_t dlen, const char *src) +/* + * NetBSD added an strnvis and unfortunately made it incompatible with the + * existing one in OpenBSD and Freedesktop's libbsd (the former having existed + * for over ten years). Despite this incompatibility being reported during + * development (see http://gnats.netbsd.org/44977) they still shipped it. + * Even more unfortunately FreeBSD and later MacOS picked up this incompatible + * implementation. + * + * Provide both implementations and default for now on the historical one to + * avoid breakage, we will switch to the NetBSD one in libbsd 0.10.0 or so. + * + * OpenBSD, 2001: strnunvis(char *dst, const char *src, size_t dlen); + * NetBSD: 2012, strnunvis(char *dst, size_t dlen, const char *src); + */ +ssize_t +strnunvis_openbsd(char *dst, const char *src, size_t dlen) { return strnunvisx(dst, dlen, src, 0); } +__asm__(".symver strnunvis_openbsd,strnunvis@@LIBBSD_0.2"); + +int +strnunvis_netbsd(char *dst, size_t dlen, const char *src) +{ + return strnunvisx(dst, dlen, src, 0); +} +__asm__(".symver strnunvis_netbsd,strnunvis@LIBBSD_0.9.1"); diff --git a/src/vis.c b/src/vis.c index 5599439..c2cd2d8 100644 --- a/src/vis.c +++ b/src/vis.c @@ -60,7 +60,10 @@ #include #include +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcpp" #include +#pragma GCC diagnostic pop #include #include #include @@ -701,11 +704,33 @@ strvis(char *mbdst, const char *mbsrc, int flags) return istrsenvisxl(&mbdst, NULL, mbsrc, flags, "", NULL); } +/* + * NetBSD added an strnvis and unfortunately made it incompatible with the + * existing one in OpenBSD and Freedesktop's libbsd (the former having existed + * for over ten years). Despite this incompatibility being reported during + * development (see http://gnats.netbsd.org/44977) they still shipped it. + * Even more unfortunately FreeBSD and later MacOS picked up this incompatible + * implementation. + * + * Provide both implementations and default for now on the historical one to + * avoid breakage, we will switch to the NetBSD one in libbsd 0.10.0 or so. + * + * OpenBSD, 2001: strnvis(char *dst, const char *src, size_t dlen, int flag); + * NetBSD: 2012, strnvis(char *dst, size_t dlen, const char *src, int flag); + */ int -strnvis(char *mbdst, size_t dlen, const char *mbsrc, int flags) +strnvis_openbsd(char *mbdst, const char *mbsrc, size_t dlen, int flags) { return istrsenvisxl(&mbdst, &dlen, mbsrc, flags, "", NULL); } +__asm__(".symver strnvis_openbsd,strnvis@@LIBBSD_0.2"); + +int +strnvis_netbsd(char *mbdst, size_t dlen, const char *mbsrc, int flags) +{ + return istrsenvisxl(&mbdst, &dlen, mbsrc, flags, "", NULL); +} +__asm__(".symver strnvis_netbsd,strnvis@LIBBSD_0.9.1"); int stravis(char **mbdstp, const char *mbsrc, int flags) diff --git a/test/.gitignore b/test/.gitignore index 256574c..47063b9 100644 --- a/test/.gitignore +++ b/test/.gitignore @@ -19,3 +19,5 @@ setmode strl strmode strnstr +vis +vis-openbsd diff --git a/test/Makefile.am b/test/Makefile.am index d86539a..452558d 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -47,6 +47,8 @@ check_PROGRAMS = \ strl \ strmode \ strnstr \ + vis \ + vis-openbsd \ $(nil) if HAVE_LIBTESTU01 diff --git a/test/vis-openbsd.c b/test/vis-openbsd.c new file mode 100644 index 0000000..99c4198 --- /dev/null +++ b/test/vis-openbsd.c @@ -0,0 +1,47 @@ +/* + * Copyright © 2018 Guillem Jover + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcpp" +#include +#pragma GCC diagnostic pop + +int +main(int argc, char **argv) +{ + char str[200]; + char unstr[200]; + + strnvis(str, "0123456789abcdef", 10, 0); + assert(strcmp(str, "0123456789") == 0); + + strnunvis(unstr, str, 100); + assert(strcmp(unstr, "0123456789") == 0); + + return 0; +} diff --git a/test/vis.c b/test/vis.c new file mode 100644 index 0000000..10b8b0f --- /dev/null +++ b/test/vis.c @@ -0,0 +1,46 @@ +/* + * Copyright © 2018 Guillem Jover + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#define LIBBSD_NETBSD_VIS 1 + +#include +#include +#include + +int +main(int argc, char **argv) +{ + char str[200]; + char unstr[200]; + + strnvis(str, 10, "0123456789abcdef", 0); + assert(strcmp(str, "0123456789") == 0); + + strnunvis(unstr, 100, str); + assert(strcmp(unstr, "0123456789") == 0); + + return 0; +}