aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Willemsen <dwillemsen@google.com>2016-06-29 23:21:20 -0700
committerDan Willemsen <dwillemsen@google.com>2016-06-29 23:21:20 -0700
commitcd29d6cc57301c7facb118077d1d059e81c3de5d (patch)
tree97bd19fe940b556297f956596ca65b0ea3872630
parentdbd6b572694f8f4d85a764282c04adc5b7577591 (diff)
downloadandroid_build_kati-cd29d6cc57301c7facb118077d1d059e81c3de5d.tar.gz
android_build_kati-cd29d6cc57301c7facb118077d1d059e81c3de5d.tar.bz2
android_build_kati-cd29d6cc57301c7facb118077d1d059e81c3de5d.zip
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.
-rw-r--r--.gitignore2
-rw-r--r--.travis.yml5
-rw-r--r--strutil_test.cc48
3 files changed, 54 insertions, 1 deletions
diff --git a/.gitignore b/.gitignore
index b907c3d..19d2723 100644
--- a/.gitignore
+++ b/.gitignore
@@ -11,8 +11,10 @@ repo/maloader/
testcase_parse_benchmark_test.go
bench-old.out
bench-new.out
+find_test
ninja_test
string_piece_test
+strutil_bench
strutil_test
go_src_stamp
version.cc
diff --git a/.travis.yml b/.travis.yml
index f045dd3..2fd6fa8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -11,7 +11,10 @@ before_script:
- sudo apt-get install -y libstdc++-4.8-dev clang-3.5 ninja-build realpath
script:
- - make -j4 ckati
+ - make -j4 ckati ckati_tests
- ruby runtest.rb -c
- ruby runtest.rb -c -n
- ruby runtest.rb -c -n -a
+ - ./ninja_test
+ - ./string_piece_test
+ - ./strutil_test
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 @@ void TestFindEndOfLine() {
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 @@ int main() {
TestNormalizePath();
TestEscapeShell();
TestFindEndOfLine();
+ TestWordScannerInvalidAccess();
+ TestFindEndOfLineInvalidAccess();
assert(!g_failed);
}