Add unit tests for invalid string accesses

A string may be allocated at the end of a page, and the next page may
not be readable, so reading beyond the null character may not be safe.
We've hit this with real makefiles, but here's a directed test that can
reproduce it in other environments.

This also updates the travis config to run the unit tests.
diff --git a/strutil_test.cc b/strutil_test.cc
index a89786f..d7290d1 100644
--- a/strutil_test.cc
+++ b/strutil_test.cc
@@ -17,6 +17,8 @@
 #include "strutil.h"
 
 #include <assert.h>
+#include <sys/mman.h>
+#include <unistd.h>
 
 #include <string>
 #include <vector>
@@ -138,6 +140,50 @@
   ASSERT_EQ(FindEndOfLine(StringPiece(buf, 2), 0, &lf_cnt), 2);
 }
 
+// Take a string, and copy it into an allocated buffer where
+// the byte immediately after the null termination character
+// is read protected. Useful for testing, but doesn't support
+// freeing the allocated pages.
+const char* CreateProtectedString(const char* str) {
+  int pagesize = sysconf(_SC_PAGE_SIZE);
+  void *buffer;
+  char *buffer_str;
+
+  // Allocate two pages of memory
+  if (posix_memalign(&buffer, pagesize, pagesize * 2) != 0) {
+    perror("posix_memalign failed");
+    assert(false);
+  }
+
+  // Make the second page unreadable
+  buffer_str = (char*)buffer + pagesize;
+  if (mprotect(buffer_str, pagesize, PROT_NONE) != 0) {
+    perror("mprotect failed");
+    assert(false);
+  }
+
+  // Then move the test string into the very end of the first page
+  buffer_str -= strlen(str) + 1;
+  strcpy(buffer_str, str);
+
+  return buffer_str;
+}
+
+void TestWordScannerInvalidAccess() {
+  vector<StringPiece> ss;
+  for (StringPiece tok : WordScanner(CreateProtectedString("0123 456789"))) {
+    ss.push_back(tok);
+  }
+  assert(ss.size() == 2LU);
+  ASSERT_EQ(ss[0], "0123");
+  ASSERT_EQ(ss[1], "56789");
+}
+
+void TestFindEndOfLineInvalidAccess() {
+  size_t lf_cnt = 0;
+  ASSERT_EQ(FindEndOfLine(CreateProtectedString("a\\"), 0, &lf_cnt), 2);
+}
+
 }  // namespace
 
 int main() {
@@ -150,5 +196,7 @@
   TestNormalizePath();
   TestEscapeShell();
   TestFindEndOfLine();
+  TestWordScannerInvalidAccess();
+  TestFindEndOfLineInvalidAccess();
   assert(!g_failed);
 }