Merge "Contact proper debuggerd when crashing."
diff --git a/benchmarks/benchmark_main.cpp b/benchmarks/benchmark_main.cpp
index 6d83f8a..fae09be 100644
--- a/benchmarks/benchmark_main.cpp
+++ b/benchmarks/benchmark_main.cpp
@@ -22,7 +22,7 @@
 #include <time.h>
 
 #include <string>
-#include <map>
+#include <vector>
 
 #include <inttypes.h>
 
@@ -38,6 +38,41 @@
   return benchmarks;
 }
 
+// Similar to the code in art, but supporting both binary and decimal prefixes.
+static std::string PrettyInt(uint64_t count, size_t base) {
+  if (base != 2 && base != 10) abort();
+
+  // The byte thresholds at which we display amounts. A count is displayed
+  // in unit U when kUnitThresholds[U] <= bytes < kUnitThresholds[U+1].
+  static const uint64_t kUnitThresholds2[] = {
+    1024*1024*1024 /* Gi */, 2*1024*1024 /* Mi */, 3*1024 /* Ki */, 0,
+  };
+  static const uint64_t kUnitThresholds10[] = {
+    1000*1000*1000 /* G */, 2*1000*1000 /* M */, 3*1000 /* k */, 0,
+  };
+  static const uint64_t kAmountPerUnit2[] = { 1024*1024*1024, 1024*1024, 1024, 1 };
+  static const uint64_t kAmountPerUnit10[] = { 1000*1000*1000, 1000*1000, 1000, 1 };
+  static const char* const kUnitStrings2[] = { "Gi", "Mi", "Ki", "" };
+  static const char* const kUnitStrings10[] = { "G", "M", "k", "" };
+
+  // Which set are we using?
+  const uint64_t* kUnitThresholds = ((base == 2) ? kUnitThresholds2 : kUnitThresholds10);
+  const uint64_t* kAmountPerUnit = ((base == 2) ? kAmountPerUnit2 : kAmountPerUnit10);
+  const char* const* kUnitStrings = ((base == 2) ? kUnitStrings2 : kUnitStrings10);
+
+  size_t i = 0;
+  for (; kUnitThresholds[i] != 0; ++i) {
+    if (count >= kUnitThresholds[i]) {
+      break;
+    }
+  }
+  char* s = NULL;
+  asprintf(&s, "%" PRId64 "%s", count / kAmountPerUnit[i], kUnitStrings[i]);
+  std::string result(s);
+  free(s);
+  return result;
+}
+
 static int Round(int n) {
   int base = 1;
   while (base*10 < n) {
@@ -154,27 +189,25 @@
 
   char throughput[100];
   throughput[0] = '\0';
+
   if (g_benchmark_total_time_ns > 0 && g_bytes_processed > 0) {
-    double mib_processed = static_cast<double>(g_bytes_processed)/1e6;
+    double gib_processed = static_cast<double>(g_bytes_processed)/1e9;
     double seconds = static_cast<double>(g_benchmark_total_time_ns)/1e9;
-    snprintf(throughput, sizeof(throughput), " %8.2f MiB/s", mib_processed/seconds);
+    snprintf(throughput, sizeof(throughput), " %8.3f GiB/s", gib_processed/seconds);
   }
 
   char full_name[100];
   if (fn_range_ != NULL) {
-    if (arg >= (1<<20)) {
-      snprintf(full_name, sizeof(full_name), "%s/%dM", name_, arg/(1<<20));
-    } else if (arg >= (1<<10)) {
-      snprintf(full_name, sizeof(full_name), "%s/%dK", name_, arg/(1<<10));
-    } else {
-      snprintf(full_name, sizeof(full_name), "%s/%d", name_, arg);
-    }
+    snprintf(full_name, sizeof(full_name), "%s/%s", name_, PrettyInt(arg, 2).c_str());
   } else {
     snprintf(full_name, sizeof(full_name), "%s", name_);
   }
 
-  printf("%-*s %10d %10" PRId64 "%s\n", g_name_column_width, full_name,
-         iterations, g_benchmark_total_time_ns/iterations, throughput);
+  printf("%-*s %10s %10" PRId64 "%s\n",
+         g_name_column_width, full_name,
+         PrettyInt(iterations, 10).c_str(),
+         g_benchmark_total_time_ns/iterations,
+         throughput);
   fflush(stdout);
 }
 
diff --git a/benchmarks/stdio_benchmark.cpp b/benchmarks/stdio_benchmark.cpp
index 386ea04..fe25d76 100644
--- a/benchmarks/stdio_benchmark.cpp
+++ b/benchmarks/stdio_benchmark.cpp
@@ -65,3 +65,13 @@
   ReadWriteTest(iters, chunk_size, fwrite, false);
 }
 BENCHMARK(BM_stdio_fwrite_unbuffered)->AT_COMMON_SIZES;
+
+static void BM_stdio_fopen_fgets_fclose(int iters) {
+  char buf[1024];
+  for (int i = 0; i < iters; ++i) {
+    FILE* fp = fopen("/proc/version", "re");
+    fgets(buf, sizeof(buf), fp);
+    fclose(fp);
+  }
+}
+BENCHMARK(BM_stdio_fopen_fgets_fclose);
diff --git a/libc/Android.mk b/libc/Android.mk
index cc1585c..e96bcff 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -61,6 +61,7 @@
     stdio/fread.c \
     stdio/snprintf.c\
     stdio/sprintf.c \
+    stdio/stdio.c \
     stdio/stdio_ext.cpp \
 
 # Fortify implementations of libc functions.
@@ -450,7 +451,6 @@
     upstream-openbsd/lib/libc/stdio/setbuffer.c \
     upstream-openbsd/lib/libc/stdio/setvbuf.c \
     upstream-openbsd/lib/libc/stdio/sscanf.c \
-    upstream-openbsd/lib/libc/stdio/stdio.c \
     upstream-openbsd/lib/libc/stdio/swprintf.c \
     upstream-openbsd/lib/libc/stdio/swscanf.c \
     upstream-openbsd/lib/libc/stdio/tempnam.c \
diff --git a/libc/dns/resolv/res_cache.c b/libc/dns/resolv/res_cache.c
index 15d04c2..c431835 100644
--- a/libc/dns/resolv/res_cache.c
+++ b/libc/dns/resolv/res_cache.c
@@ -1090,7 +1090,7 @@
         XLOG("ns_parserr failed. %s\n", strerror(errno));
     }
 
-    XLOG("TTL = %d\n", result);
+    XLOG("TTL = %lu\n", result);
 
     return result;
 }
diff --git a/libc/stdio/fread.c b/libc/stdio/fread.c
index e052128..baf62b9 100644
--- a/libc/stdio/fread.c
+++ b/libc/stdio/fread.c
@@ -35,6 +35,7 @@
 #include <string.h>
 #include <stdint.h>
 #include <errno.h>
+#include <sys/param.h>
 #include "local.h"
 
 #define MUL_NO_OVERFLOW	(1UL << (sizeof(size_t) * 4))
@@ -42,13 +43,8 @@
 size_t
 fread(void *buf, size_t size, size_t count, FILE *fp)
 {
-	size_t resid;
-	char *p;
-	int r;
-	size_t total;
-
 	/*
-	 * Extension:  Catch integer overflow
+	 * Extension:  Catch integer overflow.
 	 */
 	if ((size >= MUL_NO_OVERFLOW || count >= MUL_NO_OVERFLOW) &&
 	    size > 0 && SIZE_MAX / size < count) {
@@ -57,48 +53,81 @@
 		return (0);
 	}
 
+	const size_t desired_total = count * size;
+	size_t total = desired_total;
+
 	/*
 	 * ANSI and SUSv2 require a return value of 0 if size or count are 0.
 	 */
-	if ((resid = count * size) == 0)
+	if (total == 0) {
 		return (0);
+	}
+
 	FLOCKFILE(fp);
 	_SET_ORIENTATION(fp, -1);
+
+	// TODO: how can this ever happen?!
 	if (fp->_r < 0)
 		fp->_r = 0;
-	total = resid;
-	p = buf;
 
-	// BEGIN android-added
-	// Avoid pathological behavior on unbuffered files. OpenBSD
-	// will loop reading one byte then memcpying one byte!
-	if ((fp->_flags & __SNBF) != 0) {
-		// We know if we're unbuffered that our buffer is empty, so
-		// we can just read directly.
-		while (resid > 0 && (r = (*fp->_read)(fp->_cookie, p, resid)) > 0) {
-			p += r;
-			resid -= r;
-		}
-		FUNLOCKFILE(fp);
-		return ((total - resid) / size);
+	/*
+	 * Ensure _bf._size is valid.
+	 */
+	if (fp->_bf._base == NULL) {
+		__smakebuf(fp);
 	}
-	// END android-added
 
-	while (resid > (size_t)(r = fp->_r)) {
-		(void)memcpy((void *)p, (void *)fp->_p, (size_t)r);
-		fp->_p += r;
-		/* fp->_r = 0 ... done in __srefill */
-		p += r;
-		resid -= r;
+	char* dst = buf;
+
+	while (total > 0) {
+		/*
+		 * Copy data out of the buffer.
+		 */
+		size_t buffered_bytes = MIN((size_t) fp->_r, total);
+		memcpy(dst, fp->_p, buffered_bytes);
+		fp->_p += buffered_bytes;
+		fp->_r -= buffered_bytes;
+		dst += buffered_bytes;
+		total -= buffered_bytes;
+
+		/*
+		 * Are we done?
+		 */
+		if (total == 0) {
+			goto out;
+		}
+
+		/*
+		 * Do we have so much more to read that we should
+		 * avoid copying it through the buffer?
+		 */
+		if (total > (size_t) fp->_bf._size) {
+			break;
+		}
+
+		/*
+		 * Less than a buffer to go, so refill the buffer and
+		 * go around the loop again.
+		 */
 		if (__srefill(fp)) {
-			/* no more input: return partial result */
-			FUNLOCKFILE(fp);
-			return ((total - resid) / size);
+			goto out;
 		}
 	}
-	(void)memcpy((void *)p, (void *)fp->_p, resid);
-	fp->_r -= resid;
-	fp->_p += resid;
+
+	/*
+	 * Read directly into the caller's buffer.
+	 */
+	while (total > 0) {
+		ssize_t bytes_read = (*fp->_read)(fp->_cookie, dst, total);
+		if (bytes_read <= 0) {
+			fp->_flags = (fp->_r == 0) ? __SEOF : __SERR;
+			break;
+		}
+		dst += bytes_read;
+		total -= bytes_read;
+	}
+
+out:
 	FUNLOCKFILE(fp);
-	return (count);
+	return ((desired_total - total) / size);
 }
diff --git a/libc/upstream-openbsd/lib/libc/stdio/stdio.c b/libc/stdio/stdio.c
similarity index 88%
rename from libc/upstream-openbsd/lib/libc/stdio/stdio.c
rename to libc/stdio/stdio.c
index a4a27b5..13b9887 100644
--- a/libc/upstream-openbsd/lib/libc/stdio/stdio.c
+++ b/libc/stdio/stdio.c
@@ -31,6 +31,7 @@
  * SUCH DAMAGE.
  */
 
+#include <errno.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <stdio.h>
@@ -46,7 +47,7 @@
 	FILE *fp = cookie;
 	int ret;
 	
-	ret = read(fp->_file, buf, n);
+	ret = TEMP_FAILURE_RETRY(read(fp->_file, buf, n));
 	/* if the read succeeded, update the current offset */
 	if (ret >= 0)
 		fp->_offset += ret;
@@ -61,9 +62,9 @@
 	FILE *fp = cookie;
 
 	if (fp->_flags & __SAPP)
-		(void) lseek(fp->_file, (off_t)0, SEEK_END);
+		(void) TEMP_FAILURE_RETRY(lseek(fp->_file, (off_t)0, SEEK_END));
 	fp->_flags &= ~__SOFF;	/* in case FAPPEND mode is set */
-	return (write(fp->_file, buf, n));
+	return TEMP_FAILURE_RETRY(write(fp->_file, buf, n));
 }
 
 fpos_t
@@ -72,7 +73,7 @@
 	FILE *fp = cookie;
 	off_t ret;
 	
-	ret = lseek(fp->_file, (off_t)offset, whence);
+	ret = TEMP_FAILURE_RETRY(lseek(fp->_file, (off_t)offset, whence));
 	if (ret == (off_t)-1)
 		fp->_flags &= ~__SOFF;
 	else {
@@ -85,5 +86,5 @@
 int
 __sclose(void *cookie)
 {
-	return (close(((FILE *)cookie)->_file));
+	return TEMP_FAILURE_RETRY(close(((FILE *)cookie)->_file));
 }
diff --git a/tests/Android.mk b/tests/Android.mk
index 38d85f8..3150655 100644
--- a/tests/Android.mk
+++ b/tests/Android.mk
@@ -212,19 +212,36 @@
 include $(LOCAL_PATH)/Android.build.mk
 
 # -----------------------------------------------------------------------------
+# Library of bionic customized gtest main function.
+# -----------------------------------------------------------------------------
+libBionicGtestMain_src_files := gtest_main.cpp
+
+libBionicGtestMain_cflags := $(test_cflags)
+
+libBionicGtestMain_cppflags := $(test_cppflags)
+
+module := libBionicGtestMain
+module_tag := optional
+build_type := target
+build_target := STATIC_TEST_LIBRARY
+include $(LOCAL_PATH)/Android.build.mk
+build_type := host
+include $(LOCAL_PATH)/Android.build.mk
+
+# -----------------------------------------------------------------------------
 # Tests for the device using bionic's .so. Run with:
 #   adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests32
 #   adb shell /data/nativetest/bionic-unit-tests/bionic-unit-tests64
 # -----------------------------------------------------------------------------
 bionic-unit-tests_whole_static_libraries := \
     libBionicTests \
+    libBionicGtestMain \
 
 bionic-unit-tests_static_libraries := \
     libtinyxml2 \
     liblog \
 
 bionic-unit-tests_src_files := \
-    gtest_main.cpp \
     atexit_test.cpp \
     dl_test.cpp \
     dlext_test.cpp \
@@ -268,6 +285,7 @@
 # -----------------------------------------------------------------------------
 bionic-unit-tests-static_whole_static_libraries := \
     libBionicTests \
+    libBionicGtestMain \
 
 bionic-unit-tests-static_static_libraries := \
     libm \
@@ -277,9 +295,6 @@
     libtinyxml2 \
     liblog \
 
-bionic-unit-tests-static_src_files := \
-    gtest_main.cpp \
-
 bionic-unit-tests-static_force_static_executable := true
 
 # libc and libc++ both define std::nothrow. libc's is a private symbol, but this
@@ -302,7 +317,6 @@
 ifeq ($(HOST_OS)-$(HOST_ARCH),$(filter $(HOST_OS)-$(HOST_ARCH),linux-x86 linux-x86_64))
 
 bionic-unit-tests-glibc_src_files := \
-    gtest_main.cpp \
     atexit_test.cpp \
     dlfcn_test.cpp \
     dl_test.cpp \
@@ -315,6 +329,7 @@
 
 bionic-unit-tests-glibc_whole_static_libraries := \
     libBionicStandardTests \
+    libBionicGtestMain \
 
 bionic-unit-tests-glibc_ldlibs := \
     -lrt -ldl -lutil \
diff --git a/tests/gtest_main.cpp b/tests/gtest_main.cpp
index 6c5023b..99cd4ee 100644
--- a/tests/gtest_main.cpp
+++ b/tests/gtest_main.cpp
@@ -319,18 +319,6 @@
   fflush(stdout);
 }
 
-static void TestcaseTimePrint(const TestCase& testcase) {
-  int64_t testcase_time = 0;
-  for (size_t i = 0; i < testcase.TestCount(); ++i) {
-    testcase_time += testcase.GetTestTime(i);
-  }
-  printf("%zu %s from %s (%lld ms total)\n", testcase.TestCount(),
-                                             (testcase.TestCount() == 1) ? "test" : "tests",
-                                             testcase.GetName().c_str(),
-                                             testcase_time / 1000000LL);
-  fflush(stdout);
-}
-
 static void OnTestIterationEndPrint(const std::vector<TestCase>& testcase_list, size_t /*iteration*/,
                                     int64_t elapsed_time) {
 
@@ -364,10 +352,6 @@
     }
   }
 
-  for (auto const& testcase : testcase_list) {
-    TestcaseTimePrint(testcase);
-  }
-
   ColoredPrintf(COLOR_GREEN,  "[==========] ");
   printf("%zu %s from %zu %s ran.", test_count, (test_count == 1) ? "test" : "tests",
                                     testcase_count, (testcase_count == 1) ? "test case" : "test cases");
diff --git a/tests/stdio_ext_test.cpp b/tests/stdio_ext_test.cpp
index 3dbc485..950c7ed 100644
--- a/tests/stdio_ext_test.cpp
+++ b/tests/stdio_ext_test.cpp
@@ -34,7 +34,13 @@
 TEST(stdio_ext, __fbufsize) {
   FILE* fp = fopen("/proc/version", "r");
 
+  // Initially, there's no buffer in case the first thing you do is disable buffering.
+  ASSERT_EQ(0U, __fbufsize(fp));
+
+  // A read forces a buffer to be created.
   char buf[128];
+  fgets(buf, sizeof(buf), fp);
+  ASSERT_EQ(1024U, __fbufsize(fp));
 
   ASSERT_EQ(0, setvbuf(fp, buf, _IOFBF, 1));
   ASSERT_EQ(1U, __fbufsize(fp));
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index de5eea3..6d7e72b 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -888,3 +888,25 @@
     ASSERT_EQ('\xff', buf[i]);
   }
 }
+
+TEST(fread, fread_EOF) {
+  const char* digits = "0123456789";
+  FILE* fp = fmemopen((char*) digits, sizeof(digits), "r");
+
+  // Try to read too much, but little enough that it still fits in the FILE's internal buffer.
+  char buf1[4 * 4];
+  memset(buf1, 0, sizeof(buf1));
+  ASSERT_EQ(2U, fread(buf1, 4, 4, fp));
+  ASSERT_STREQ(buf1, "01234567");
+  ASSERT_TRUE(feof(fp));
+
+  rewind(fp);
+
+  char buf2[4 * 4];
+  memset(buf2, 0, sizeof(buf2));
+  ASSERT_EQ(2U, fread(buf2, 4, 4096, fp));
+  ASSERT_STREQ(buf2, "01234567");
+  ASSERT_TRUE(feof(fp));
+
+  fclose(fp);
+}
diff --git a/tests/sys_resource_test.cpp b/tests/sys_resource_test.cpp
index 91d07ab..8cefc65 100644
--- a/tests/sys_resource_test.cpp
+++ b/tests/sys_resource_test.cpp
@@ -14,11 +14,11 @@
  * limitations under the License.
  */
 
-#include <gtest/gtest.h>
-
 #include <sys/resource.h>
 
-TEST(sys_resource, smoke) {
+#include <gtest/gtest.h>
+
+TEST(sys_resource, rlimit_struct_size) {
 #if defined(__LP64__) || defined(__GLIBC__)
   ASSERT_EQ(sizeof(rlimit), sizeof(rlimit64));
   ASSERT_EQ(8U, sizeof(rlim_t));
@@ -26,51 +26,75 @@
   ASSERT_NE(sizeof(rlimit), sizeof(rlimit64));
   ASSERT_EQ(4U, sizeof(rlim_t));
 #endif
+}
 
-  // Read with getrlimit, getrlimit64, and prlimit64.
-  // (prlimit is prlimit64 on LP64 and unimplemented on 32-bit.)
-  rlimit l32;
-  rlimit64 l64;
-  rlimit64 pr_l64;
-  ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32));
-  ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64));
-  ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64));
-  ASSERT_EQ(l64.rlim_cur, l32.rlim_cur);
-  ASSERT_EQ(l64.rlim_cur, pr_l64.rlim_cur);
-  ASSERT_EQ(l64.rlim_max, pr_l64.rlim_max);
-  if (l64.rlim_max == RLIM64_INFINITY) {
-    ASSERT_EQ(RLIM_INFINITY, l32.rlim_max);
-  } else {
-    ASSERT_EQ(l64.rlim_max, l32.rlim_max);
+class SysResourceTest : public ::testing::Test {
+ protected:
+  virtual void SetUp() {
+    ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32_));
+    ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64_));
+    ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64_));
   }
 
-  // Write with setrlimit and read back with everything.
-  l32.rlim_cur = 123;
-  ASSERT_EQ(0, setrlimit(RLIMIT_CORE, &l32));
-  ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32));
-  ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64));
-  ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64));
-  ASSERT_EQ(123U, l32.rlim_cur);
-  ASSERT_EQ(l64.rlim_cur, l32.rlim_cur);
-  ASSERT_EQ(l64.rlim_cur, pr_l64.rlim_cur);
+  void CheckResourceLimits();
 
-  // Write with setrlimit64 and read back with everything.
-  l64.rlim_cur = 456;
-  ASSERT_EQ(0, setrlimit64(RLIMIT_CORE, &l64));
-  ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32));
-  ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64));
-  ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64));
-  ASSERT_EQ(456U, l32.rlim_cur);
-  ASSERT_EQ(l64.rlim_cur, l32.rlim_cur);
-  ASSERT_EQ(l64.rlim_cur, pr_l64.rlim_cur);
+ protected:
+  rlimit l32_;
+  rlimit64 l64_;
+  rlimit64 pr_l64_;
+};
 
-  // Write with prlimit64 and read back with everything.
-  l64.rlim_cur = 789;
-  ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, &l64, NULL));
-  ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32));
-  ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64));
-  ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64));
-  ASSERT_EQ(789U, l32.rlim_cur);
-  ASSERT_EQ(l64.rlim_cur, l32.rlim_cur);
-  ASSERT_EQ(l64.rlim_cur, pr_l64.rlim_cur);
+void SysResourceTest::CheckResourceLimits() {
+  ASSERT_EQ(0, getrlimit(RLIMIT_CORE, &l32_));
+  ASSERT_EQ(0, getrlimit64(RLIMIT_CORE, &l64_));
+  ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, NULL, &pr_l64_));
+  ASSERT_EQ(l64_.rlim_cur, pr_l64_.rlim_cur);
+  if (l64_.rlim_cur == RLIM64_INFINITY) {
+    ASSERT_EQ(RLIM_INFINITY, l32_.rlim_cur);
+  } else {
+    ASSERT_EQ(l64_.rlim_cur, l32_.rlim_cur);
+  }
+
+  ASSERT_EQ(l64_.rlim_max, pr_l64_.rlim_max);
+  if (l64_.rlim_max == RLIM64_INFINITY) {
+    ASSERT_EQ(RLIM_INFINITY, l32_.rlim_max);
+  } else {
+    ASSERT_EQ(l64_.rlim_max, l32_.rlim_max);
+  }
+}
+
+// Force rlim_max to be bigger than a constant so we can continue following test.
+// Change resource limit setting with "ulimit -Hc" in the shell if this test fails.
+TEST_F(SysResourceTest, RLIMIT_CORE_rlim_max_not_zero) {
+  ASSERT_TRUE(l32_.rlim_max == RLIM_INFINITY || l32_.rlim_max >= 456U) <<
+    "RLIMIT_CORE rlim_max = " << l32_.rlim_max;
+}
+
+TEST_F(SysResourceTest, get_resource_limit_equal) {
+  CheckResourceLimits();
+}
+
+TEST_F(SysResourceTest, setrlimit) {
+  l32_.rlim_cur = 123U;
+  ASSERT_EQ(0, setrlimit(RLIMIT_CORE, &l32_));
+  CheckResourceLimits();
+  ASSERT_EQ(123U, l32_.rlim_cur);
+}
+
+TEST_F(SysResourceTest, setrlimit64) {
+  l64_.rlim_cur = 456U;
+  ASSERT_EQ(0, setrlimit64(RLIMIT_CORE, &l64_));
+  CheckResourceLimits();
+  ASSERT_EQ(456U, l64_.rlim_cur);
+}
+
+TEST_F(SysResourceTest, prlimit64) {
+  pr_l64_.rlim_cur = pr_l64_.rlim_max;
+  ASSERT_EQ(0, prlimit64(0, RLIMIT_CORE, &pr_l64_, NULL));
+  CheckResourceLimits();
+  ASSERT_EQ(pr_l64_.rlim_max, pr_l64_.rlim_cur);
+}
+
+TEST_F(SysResourceTest, prlimit) {
+  // prlimit is prlimit64 on LP64 and unimplemented on 32-bit. So we only test prlimit64.
 }
diff --git a/tools/bionicbb/gmail_listener.py b/tools/bionicbb/gmail_listener.py
index 6a8b9e6..f4936d6 100644
--- a/tools/bionicbb/gmail_listener.py
+++ b/tools/bionicbb/gmail_listener.py
@@ -297,6 +297,13 @@
     except NotImplementedError as ex:
         print ex
         return False
+    except gerrit.GerritError as ex:
+        if ex.code == 404:
+            print '{}(404): {}!'.format(
+                termcolor.colored('ERROR', 'red'), ex)
+            return True
+        else:
+            return False
 
 
 def main(argc, argv):