From 521fbe9135ce7eefd190f8a2c50b00be428def6c Mon Sep 17 00:00:00 2001
From: Jon Turney <jon.turney@dronecode.org.uk>
Date: Wed, 9 Apr 2014 23:49:03 +0100
Subject: [PATCH 17/29] Provide a working strtok_r for MinGW

Prior to mingW-w64 3.3.0, strtok_r was a macro using strtok, which causes the
processor to not work, as re-entrancy is required

v2:
Link various unit tests with @LIBOBJS@ for strtok_r

Signed-off-by: Jon Turney <jon.turney@dronecode.org.uk>
---
 Makefile.am                                 | 28 +++++-----
 compat/strtok_r.c                           | 85 +++++++++++++++++++++++++++++
 configure.ac                                |  3 +
 src/processor/basic_source_line_resolver.cc |  4 ++
 src/processor/cfi_frame_info.cc             |  6 +-
 src/processor/tokenize.cc                   |  6 +-
 6 files changed, 116 insertions(+), 16 deletions(-)
 create mode 100644 compat/strtok_r.c

diff --git a/Makefile.am b/Makefile.am
index 39aec328..43d28f6a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -833,7 +833,7 @@ src_processor_basic_source_line_resolver_unittest_LDADD = \
 	src/processor/source_line_resolver_base.o \
 	src/processor/tokenize.o \
 	$(TEST_LIBS) \
-	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
+	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) @LIBOBJS@
 
 src_processor_cfi_frame_info_unittest_SOURCES = \
 	src/processor/cfi_frame_info_unittest.cc
@@ -842,7 +842,7 @@ src_processor_cfi_frame_info_unittest_LDADD = \
 	src/processor/logging.o \
 	src/processor/pathname_stripper.o \
 	$(TEST_LIBS) \
-	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
+	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) @LIBOBJS@
 src_processor_cfi_frame_info_unittest_CPPFLAGS = \
 	$(AM_CPPFLAGS) $(TEST_CFLAGS)
 
@@ -891,7 +891,7 @@ src_processor_exploitability_unittest_LDADD = \
 	src/processor/tokenize.o \
 	src/third_party/libdisasm/libdisasm.a \
 	$(TEST_LIBS) \
-	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
+	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) @LIBOBJS@
 
 src_processor_disassembler_x86_unittest_SOURCES = \
 	src/processor/disassembler_x86_unittest.cc
@@ -918,7 +918,7 @@ src_processor_fast_source_line_resolver_unittest_LDADD = \
 	src/processor/source_line_resolver_base.o \
 	src/processor/tokenize.o \
 	$(TEST_LIBS) \
-	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
+	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) @LIBOBJS@
 
 src_processor_map_serializers_unittest_SOURCES = \
 	src/processor/map_serializers_unittest.cc
@@ -961,7 +961,7 @@ src_processor_microdump_processor_unittest_LDADD = \
 	src/processor/stackwalker_x86.o \
 	src/processor/tokenize.o \
 	$(TEST_LIBS) \
-	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
+	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) @LIBOBJS@
 
 src_processor_minidump_processor_unittest_SOURCES = \
 	src/processor/minidump_processor_unittest.cc
@@ -1001,7 +1001,7 @@ src_processor_minidump_processor_unittest_LDADD = \
 	src/processor/tokenize.o \
 	src/third_party/libdisasm/libdisasm.a \
 	$(TEST_LIBS) \
-	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
+	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) @LIBOBJS@
 
 src_processor_minidump_unittest_SOURCES = \
 	src/common/test_assembler.cc \
@@ -1138,7 +1138,7 @@ src_processor_stackwalker_amd64_unittest_SOURCES = \
 src_processor_stackwalker_amd64_unittest_LDADD = \
 	src/libbreakpad.a \
 	$(TEST_LIBS) \
-	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
+	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) @LIBOBJS@
 src_processor_stackwalker_amd64_unittest_CPPFLAGS = \
 	$(AM_CPPFLAGS) $(TEST_CFLAGS)
 
@@ -1148,7 +1148,7 @@ src_processor_stackwalker_arm_unittest_SOURCES = \
 src_processor_stackwalker_arm_unittest_LDADD = \
 	src/libbreakpad.a \
 	$(TEST_LIBS) \
-	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
+	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) @LIBOBJS@
 src_processor_stackwalker_arm_unittest_CPPFLAGS = \
 	$(AM_CPPFLAGS) $(TEST_CFLAGS)
 
@@ -1158,7 +1158,7 @@ src_processor_stackwalker_arm64_unittest_SOURCES = \
 src_processor_stackwalker_arm64_unittest_LDADD = \
 	src/libbreakpad.a \
 	$(TEST_LIBS) \
-	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
+	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) @LIBOBJS@
 src_processor_stackwalker_arm64_unittest_CPPFLAGS = \
 	$(AM_CPPFLAGS) $(TEST_CFLAGS)
 
@@ -1168,7 +1168,7 @@ src_processor_stackwalker_address_list_unittest_SOURCES = \
 src_processor_stackwalker_address_list_unittest_LDADD = \
 	src/libbreakpad.a \
 	$(TEST_LIBS) \
-	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
+	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) @LIBOBJS@
 src_processor_stackwalker_address_list_unittest_CPPFLAGS = \
 	$(AM_CPPFLAGS) $(TEST_CFLAGS)
 
@@ -1178,7 +1178,7 @@ src_processor_stackwalker_mips_unittest_SOURCES = \
 src_processor_stackwalker_mips_unittest_LDADD = \
 	src/libbreakpad.a \
 	$(TEST_LIBS) \
-	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
+	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) @LIBOBJS@
 src_processor_stackwalker_mips_unittest_CPPFLAGS = \
 	$(AM_CPPFLAGS) $(TEST_CFLAGS)
 
@@ -1198,7 +1198,7 @@ src_processor_stackwalker_x86_unittest_SOURCES = \
 src_processor_stackwalker_x86_unittest_LDADD = \
 	src/libbreakpad.a \
 	$(TEST_LIBS) \
-	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS)
+	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) @LIBOBJS@
 src_processor_stackwalker_x86_unittest_CPPFLAGS = \
 	$(AM_CPPFLAGS) $(TEST_CFLAGS)
 
@@ -1273,7 +1273,7 @@ src_processor_microdump_stackwalk_LDADD = \
 	src/processor/stackwalker_x86.o \
 	src/processor/tokenize.o \
 	src/third_party/libdisasm/libdisasm.a \
-	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) $(SOCKET_LIBS)
+	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) $(SOCKET_LIBS) @LIBOBJS@
 
 src_processor_minidump_stackwalk_SOURCES = \
 	src/processor/minidump_stackwalk.cc
@@ -1313,7 +1313,7 @@ src_processor_minidump_stackwalk_LDADD = \
 	src/processor/symbolic_constants_win.o \
 	src/processor/tokenize.o \
 	src/third_party/libdisasm/libdisasm.a \
-	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) $(SOCKET_LIBS)
+	$(PTHREAD_CFLAGS) $(PTHREAD_LIBS) $(SOCKET_LIBS) @LIBOBJS@
 
 endif !DISABLE_PROCESSOR
 
diff --git a/compat/strtok_r.c b/compat/strtok_r.c
new file mode 100644
index 00000000..ec7b6379
--- /dev/null
+++ b/compat/strtok_r.c
@@ -0,0 +1,85 @@
+/*-
+ * Copyright (c) 1998 Softweyr LLC.  All rights reserved.
+ *
+ * strtok_r, from Berkeley strtok
+ * Oct 13, 1998 by Wes Peters <wes@softweyr.com>
+ *
+ * Copyright (c) 1988, 1993
+ *      The Regents of the University of California.  All rights reserved.
+ *
+ * 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
+ *    notices, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notices, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *      This product includes software developed by Softweyr LLC, the
+ *      University of California, Berkeley, and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY SOFTWEYR LLC, THE REGENTS AND CONTRIBUTORS
+ * ``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 SOFTWEYR LLC, THE
+ * REGENTS, OR CONTRIBUTORS 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 <string.h>
+
+char *
+strtok_r(char *s, const char *delim, char **last)
+{
+  char *spanp, *tok;
+  int c, sc;
+
+  if (s == NULL && (s = *last) == NULL)
+    return (NULL);
+
+  /*
+   * Skip (span) leading delimiters (s += strspn(s, delim), sort of).
+   */
+cont:
+  c = *s++;
+  for (spanp = (char *)delim; (sc = *spanp++) != 0;) {
+    if (c == sc)
+      goto cont;
+  }
+
+  if (c == 0) {           /* no non-delimiter characters */
+    *last = NULL;
+    return (NULL);
+  }
+  tok = s - 1;
+
+  /*
+   * Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
+   * Note that delim must have one NUL; we stop if we see that, too.
+   */
+  for (;;) {
+    c = *s++;
+    spanp = (char *)delim;
+    do {
+      if ((sc = *spanp++) == c) {
+        if (c == 0)
+          s = NULL;
+        else
+          s[-1] = '\0';
+        *last = s;
+        return (tok);
+      }
+    } while (sc != 0);
+  }
+  /* NOTREACHED */
+}
diff --git a/configure.ac b/configure.ac
index 93635de5..da8c49a3 100644
--- a/configure.ac
+++ b/configure.ac
@@ -78,6 +78,9 @@ AC_CHECK_FUNCS([arc4random getrandom])
 
 AX_CXX_COMPILE_STDCXX(11, noext, mandatory)
 
+AC_CONFIG_LIBOBJ_DIR([compat])
+AC_REPLACE_FUNCS([strtok_r])
+
 dnl Test supported warning flags.
 WARN_CXXFLAGS=
 dnl This warning flag is used by clang.  Its default behavior is to warn when
diff --git a/src/processor/basic_source_line_resolver.cc b/src/processor/basic_source_line_resolver.cc
index aa66e159..b7ee7d17 100644
--- a/src/processor/basic_source_line_resolver.cc
+++ b/src/processor/basic_source_line_resolver.cc
@@ -49,6 +49,10 @@
 
 #include "processor/tokenize.h"
 
+#ifndef HAVE_STRTOK_R
+extern "C" char *strtok_r(char *, const char *, char **);
+#endif
+
 using std::map;
 using std::vector;
 using std::make_pair;
diff --git a/src/processor/cfi_frame_info.cc b/src/processor/cfi_frame_info.cc
index 0c4af7ba..dd2b438b 100644
--- a/src/processor/cfi_frame_info.cc
+++ b/src/processor/cfi_frame_info.cc
@@ -41,12 +41,16 @@
 #include "common/scoped_ptr.h"
 #include "processor/postfix_evaluator-inl.h"
 
-namespace google_breakpad {
+#ifndef HAVE_STRTOK_R
+extern "C" char *strtok_r(char *, const char *, char **);
+#endif
 
 #ifdef _MSC_VER
 #define strtok_r strtok_s
 #endif
 
+namespace google_breakpad {
+
 template<typename V>
 bool CFIFrameInfo::FindCallerRegs(const RegisterValueMap<V> &registers,
                                   const MemoryRegion &memory,
diff --git a/src/processor/tokenize.cc b/src/processor/tokenize.cc
index 8fce87a2..e6213ac3 100644
--- a/src/processor/tokenize.cc
+++ b/src/processor/tokenize.cc
@@ -34,12 +34,16 @@
 
 #include "common/using_std_string.h"
 
-namespace google_breakpad {
+#ifndef HAVE_STRTOK_R
+extern "C" char *strtok_r(char *, const char *, char **);
+#endif
 
 #ifdef _MSC_VER
 #define strtok_r strtok_s
 #endif
 
+namespace google_breakpad {
+
 using std::vector;
 
 bool Tokenize(char *line,
-- 
2.15.0

