From e50097d233cb52551702165324514cb6018a7627 Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Wed, 10 Jun 2009 14:16:40 -0700 Subject: [PATCH] Fix glibc 2.7 strtok_r() bug in a more permanent fashion. The glibc 2.7 headers contain a bug that causes strtok_r() to segfault in some circumstances. Until now, we have been working around this problem at each invocation, but this depends on the programmer to remember to do so each time. This commit instead adds a shim that adds a work-around to the string.h header itself, so that it is much more difficult to miss the workaround. --- acinclude.m4 | 31 +++++++++++++++++++++++++++++++ configure.ac | 1 + lib/vconn-ssl.c | 8 ++------ lib/vconn-tcp.c | 8 ++------ secchan/netflow.c | 4 ++-- utilities/ovs-dpctl.c | 2 +- utilities/ovs-ofctl.c | 4 ++-- 7 files changed, 41 insertions(+), 17 deletions(-) diff --git a/acinclude.m4 b/acinclude.m4 index f16bbf4b..1e7989f0 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -154,6 +154,37 @@ AC_DEFUN([OVS_CHECK_IF_PACKET], [Define to 1 if net/if_packet.h is available.]) fi]) +dnl Checks for buggy strtok_r. +dnl +dnl Some versions of glibc 2.7 has a bug in strtok_r when compiling +dnl with optimization that can cause segfaults: +dnl +dnl http://sources.redhat.com/bugzilla/show_bug.cgi?id=5614. +AC_DEFUN([OVS_CHECK_STRTOK_R], + [AC_CACHE_CHECK( + [whether strtok_r macro segfaults on some inputs], + [ovs_cv_strtok_r_bug], + [AC_RUN_IFELSE( + [AC_LANG_PROGRAM([#include + #include + ], + [[char string[] = ":::"; + char *save_ptr = (char *) 0xc0ffee; + char *token1, *token2; + token1 = strtok_r(string, ":", &save_ptr); + token2 = strtok_r(NULL, ":", &save_ptr); + printf ("%s %s\n", token1, token2); + return 0; + ]])], + [ovs_cv_strtok_r_bug=no], + [ovs_cv_strtok_r_bug=yes], + [ovs_cv_strtok_r_bug=yes])]) + if test $ovs_cv_strtok_r_bug = yes; then + AC_DEFINE([HAVE_STRTOK_R_BUG], [1], + [Define if strtok_r macro segfaults on some inputs]) + fi +]) + dnl ---------------------------------------------------------------------- dnl These macros are from GNU PSPP, with the following original license: dnl Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc. diff --git a/configure.ac b/configure.ac index 65152d17..0cc535c6 100644 --- a/configure.ac +++ b/configure.ac @@ -46,6 +46,7 @@ OVS_CHECK_CURSES OVS_CHECK_LINUX_VT_H OVS_CHECK_PCRE OVS_CHECK_IF_PACKET +OVS_CHECK_STRTOK_R if $build_userspace; then OVS_CHECK_PKIDIR diff --git a/lib/vconn-ssl.c b/lib/vconn-ssl.c index 20bfb979..96890e6b 100644 --- a/lib/vconn-ssl.c +++ b/lib/vconn-ssl.c @@ -279,12 +279,8 @@ ssl_open(const char *name, char *suffix, struct vconn **vconnp) return retval; } - /* Glibc 2.7 has a bug in strtok_r when compiling with optimization that - * can cause segfaults here: - * http://sources.redhat.com/bugzilla/show_bug.cgi?id=5614. - * Using "::" instead of the obvious ":" works around it. */ - host_name = strtok_r(suffix, "::", &save_ptr); - port_string = strtok_r(NULL, "::", &save_ptr); + host_name = strtok_r(suffix, ":", &save_ptr); + port_string = strtok_r(NULL, ":", &save_ptr); if (!host_name) { ovs_error(0, "%s: bad peer name format", name); return EAFNOSUPPORT; diff --git a/lib/vconn-tcp.c b/lib/vconn-tcp.c index 081ac26d..3b29a290 100644 --- a/lib/vconn-tcp.c +++ b/lib/vconn-tcp.c @@ -64,12 +64,8 @@ tcp_open(const char *name, char *suffix, struct vconn **vconnp) int retval; int fd; - /* Glibc 2.7 has a bug in strtok_r when compiling with optimization that - * can cause segfaults here: - * http://sources.redhat.com/bugzilla/show_bug.cgi?id=5614. - * Using "::" instead of the obvious ":" works around it. */ - host_name = strtok_r(suffix, "::", &save_ptr); - port_string = strtok_r(NULL, "::", &save_ptr); + host_name = strtok_r(suffix, ":", &save_ptr); + port_string = strtok_r(NULL, ":", &save_ptr); if (!host_name) { ovs_error(0, "%s: bad peer name format", name); return EAFNOSUPPORT; diff --git a/secchan/netflow.c b/secchan/netflow.c index 99f3eea4..5d90eea3 100644 --- a/secchan/netflow.c +++ b/secchan/netflow.c @@ -118,8 +118,8 @@ open_collector(char *dst) * can cause segfaults here: * http://sources.redhat.com/bugzilla/show_bug.cgi?id=5614. * Using "::" instead of the obvious ":" works around it. */ - host_name = strtok_r(dst, "::", &save_ptr); - port_string = strtok_r(NULL, "::", &save_ptr); + host_name = strtok_r(dst, ":", &save_ptr); + port_string = strtok_r(NULL, ":", &save_ptr); if (!host_name) { ovs_error(0, "%s: bad peer name format", dst); return -EAFNOSUPPORT; diff --git a/utilities/ovs-dpctl.c b/utilities/ovs-dpctl.c index ccddd2f2..381c936f 100644 --- a/utilities/ovs-dpctl.c +++ b/utilities/ovs-dpctl.c @@ -281,7 +281,7 @@ do_add_if(int argc UNUSED, char *argv[]) int flags = 0; int error; - devname = strtok_r(argv[i], ",,", &save_ptr); + devname = strtok_r(argv[i], ",", &save_ptr); if (!devname) { ovs_error(0, "%s is not a valid network device name", argv[i]); continue; diff --git a/utilities/ovs-ofctl.c b/utilities/ovs-ofctl.c index 8b343956..051a88aa 100644 --- a/utilities/ovs-ofctl.c +++ b/utilities/ovs-ofctl.c @@ -457,14 +457,14 @@ str_to_ip(const char *str_, uint32_t *ip) struct in_addr in_addr; int n_wild, retval; - name = strtok_r(str, "//", &save_ptr); + name = strtok_r(str, "/", &save_ptr); retval = name ? lookup_ip(name, &in_addr) : EINVAL; if (retval) { ovs_fatal(0, "%s: could not convert to IP address", str); } *ip = in_addr.s_addr; - netmask = strtok_r(NULL, "//", &save_ptr); + netmask = strtok_r(NULL, "/", &save_ptr); if (netmask) { uint8_t o[4]; if (sscanf(netmask, "%"SCNu8".%"SCNu8".%"SCNu8".%"SCNu8, -- 2.30.2