Merge "Get the full set of PRNG functions in <stdlib.h>"
diff --git a/benchmarks/benchmark_main.cpp b/benchmarks/benchmark_main.cpp
index cd80968..d60670b 100644
--- a/benchmarks/benchmark_main.cpp
+++ b/benchmarks/benchmark_main.cpp
@@ -32,7 +32,7 @@
 typedef std::map<std::string, ::testing::Benchmark*> BenchmarkMap;
 typedef BenchmarkMap::iterator BenchmarkMapIt;
 static BenchmarkMap g_benchmarks;
-static size_t g_name_column_width = 20;
+static int g_name_column_width = 20;
 
 static int Round(int n) {
   int base = 1;
@@ -196,7 +196,8 @@
   }
 
   for (BenchmarkMapIt it = g_benchmarks.begin(); it != g_benchmarks.end(); ++it) {
-    g_name_column_width = std::max(g_name_column_width, strlen(it->second->Name()));
+    int name_width = static_cast<int>(strlen(it->second->Name()));
+    g_name_column_width = std::max(g_name_column_width, name_width);
   }
 
   bool need_header = true;
diff --git a/libc/Android.mk b/libc/Android.mk
index 30e6419..e3fb2a1 100644
--- a/libc/Android.mk
+++ b/libc/Android.mk
@@ -421,7 +421,6 @@
     upstream-openbsd/lib/libc/stdio/putc.c \
     upstream-openbsd/lib/libc/stdio/putchar.c \
     upstream-openbsd/lib/libc/stdio/puts.c \
-    upstream-openbsd/lib/libc/stdio/putw.c \
     upstream-openbsd/lib/libc/stdio/putwc.c \
     upstream-openbsd/lib/libc/stdio/putwchar.c \
     upstream-openbsd/lib/libc/stdio/refill.c \
diff --git a/libc/arch-arm/arm.mk b/libc/arch-arm/arm.mk
index 7c423ab..260d72e 100644
--- a/libc/arch-arm/arm.mk
+++ b/libc/arch-arm/arm.mk
@@ -5,6 +5,7 @@
     bionic/legacy_32_bit_support.cpp \
     bionic/ndk_cruft.cpp \
     bionic/time64.c \
+    upstream-openbsd/lib/libc/stdio/putw.c \
 
 # These are shared by all the 32-bit targets, but not the 64-bit ones.
 libc_bionic_src_files_arm := \
diff --git a/libc/arch-mips/mips.mk b/libc/arch-mips/mips.mk
index 64b0fb2..c964e67 100644
--- a/libc/arch-mips/mips.mk
+++ b/libc/arch-mips/mips.mk
@@ -5,6 +5,7 @@
     bionic/legacy_32_bit_support.cpp \
     bionic/ndk_cruft.cpp \
     bionic/time64.c \
+    upstream-openbsd/lib/libc/stdio/putw.c \
 
 # These are shared by all the 32-bit targets, but not the 64-bit ones.
 libc_bionic_src_files_mips += \
diff --git a/libc/arch-x86/x86.mk b/libc/arch-x86/x86.mk
index 0f22169..3dc71d1 100644
--- a/libc/arch-x86/x86.mk
+++ b/libc/arch-x86/x86.mk
@@ -5,6 +5,7 @@
     bionic/legacy_32_bit_support.cpp \
     bionic/ndk_cruft.cpp \
     bionic/time64.c \
+    upstream-openbsd/lib/libc/stdio/putw.c \
 
 # Fortify implementations of libc functions.
 libc_common_src_files_x86 += \
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index efc5492..62acb3a 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -337,8 +337,6 @@
 		__printflike(2, 3);
 char	*fgetln(FILE * __restrict, size_t * __restrict);
 int	 fpurge(FILE *);
-int	 getw(FILE *);
-int	 putw(int, FILE *);
 void	 setbuffer(FILE *, char *, int);
 int	 setlinebuf(FILE *);
 int	 vasprintf(char ** __restrict, const char * __restrict,
diff --git a/tests/TemporaryFile.h b/tests/TemporaryFile.h
index a7b13b0..c4ee2d5 100644
--- a/tests/TemporaryFile.h
+++ b/tests/TemporaryFile.h
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <fcntl.h>
 #include <unistd.h>
 
 template<int (*mk_fn)(char*)>
@@ -39,6 +40,11 @@
     unlink(filename);
   }
 
+  void reopen() {
+    close(fd);
+    fd = open(filename, O_RDWR);
+  }
+
   int fd;
   char filename[1024];
 
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index e291f52..18dae9c 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -532,10 +532,6 @@
 #endif
 
   errno = 0;
-  EXPECT_EQ(EOF, putw(1234, fp));
-  EXPECT_EQ(EBADF, errno);
-
-  errno = 0;
   EXPECT_EQ(0U, fwrite("hello", 1, 2, fp));
   EXPECT_EQ(EBADF, errno);
 
diff --git a/tests/sys_mman_test.cpp b/tests/sys_mman_test.cpp
index 6ac279f..75ccfa3 100644
--- a/tests/sys_mman_test.cpp
+++ b/tests/sys_mman_test.cpp
@@ -17,14 +17,158 @@
 #include <gtest/gtest.h>
 
 #include <sys/mman.h>
+#include <sys/types.h>
 #include <unistd.h>
 
-TEST(sys_mman, mmap_negative) {
-  off_t off = -sysconf(_SC_PAGE_SIZE); // Aligned but negative.
-  ASSERT_EQ(MAP_FAILED, mmap(NULL, 4096, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, off));
+#include "TemporaryFile.h"
+
+TEST(sys_mman, mmap_std) {
+  void* map = mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
+  ASSERT_NE(MAP_FAILED, map);
+  ASSERT_EQ(0, munmap(map, 4096));
 }
 
-TEST(sys_mman, mmap64_negative) {
-  off64_t off64 = -sysconf(_SC_PAGE_SIZE); // Aligned but negative.
-  ASSERT_EQ(MAP_FAILED, mmap64(NULL, 4096, PROT_READ|PROT_WRITE, MAP_ANON|MAP_PRIVATE, -1, off64));
+TEST(sys_mman, mmap64_std) {
+  void* map = mmap64(NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
+  ASSERT_NE(MAP_FAILED, map);
+  ASSERT_EQ(0, munmap(map, 4096));
+}
+
+TEST(sys_mman, mmap_file_bad_offset) {
+  TemporaryFile tf;
+
+  void* map = mmap(NULL, 100, PROT_READ, MAP_SHARED, tf.fd, 1);
+  ASSERT_EQ(MAP_FAILED, map);
+}
+
+TEST(sys_mman, mmap64_file_bad_offset) {
+  TemporaryFile tf;
+
+  void* map = mmap64(NULL, 100, PROT_READ, MAP_SHARED, tf.fd, 1);
+  ASSERT_EQ(MAP_FAILED, map);
+}
+
+#define STR_SSIZE(str) static_cast<ssize_t>(sizeof(str))
+
+#define STRING_MSG  "012345678\nabcdefgh\n"
+#define INITIAL_MSG "000000000\n00000000\n"
+
+TEST(sys_mman, mmap_file_read) {
+  TemporaryFile tf;
+
+  ASSERT_EQ(STR_SSIZE(STRING_MSG), write(tf.fd, STRING_MSG, sizeof(STRING_MSG)));
+
+  void* map = mmap(NULL, sizeof(STRING_MSG), PROT_READ, MAP_SHARED, tf.fd, 0);
+  ASSERT_NE(MAP_FAILED, map);
+
+  char* data = reinterpret_cast<char*>(map);
+  ASSERT_STREQ(STRING_MSG, data);
+
+  ASSERT_EQ(0, munmap(map, sizeof(STRING_MSG)));
+}
+
+TEST(sys_mman, mmap_file_write) {
+  TemporaryFile tf;
+
+  ASSERT_EQ(STR_SSIZE(INITIAL_MSG), write(tf.fd, INITIAL_MSG, sizeof(INITIAL_MSG)));
+  lseek(tf.fd, 0, SEEK_SET);
+
+  void* map = mmap(NULL, sizeof(STRING_MSG), PROT_WRITE, MAP_SHARED, tf.fd, 0);
+  ASSERT_NE(MAP_FAILED, map);
+  close(tf.fd);
+
+  memcpy(map, STRING_MSG, sizeof(STRING_MSG));
+
+  ASSERT_EQ(0, munmap(map, sizeof(STRING_MSG)));
+
+  tf.reopen();
+  char buf[sizeof(STRING_MSG)];
+  memset(buf, 0, sizeof(STRING_MSG));
+  ASSERT_EQ(STR_SSIZE(STRING_MSG), read(tf.fd, buf, sizeof(STRING_MSG)));
+
+  ASSERT_STREQ(STRING_MSG, buf);
+}
+
+#define PAGE0_MSG "00PAGE00"
+#define PAGE1_MSG "111PAGE111"
+#define PAGE2_MSG "2222PAGE2222"
+#define END_MSG "E"
+
+TEST(sys_mman, mmap_file_read_at_offset) {
+  TemporaryFile tf;
+  size_t pagesize = sysconf(_SC_PAGESIZE);
+
+  // Create the file with three pages worth of data.
+  ASSERT_EQ(STR_SSIZE(PAGE0_MSG), write(tf.fd, PAGE0_MSG, sizeof(PAGE0_MSG)));
+  ASSERT_NE(-1, lseek(tf.fd, pagesize, SEEK_SET));
+  ASSERT_EQ(STR_SSIZE(PAGE1_MSG), write(tf.fd, PAGE1_MSG, sizeof(PAGE1_MSG)));
+  ASSERT_NE(-1, lseek(tf.fd, 2 * pagesize, SEEK_SET));
+  ASSERT_EQ(STR_SSIZE(PAGE2_MSG), write(tf.fd, PAGE2_MSG, sizeof(PAGE2_MSG)));
+  ASSERT_NE(-1, lseek(tf.fd, 3 * pagesize - sizeof(END_MSG), SEEK_SET));
+  ASSERT_EQ(STR_SSIZE(END_MSG), write(tf.fd, END_MSG, sizeof(END_MSG)));
+
+  ASSERT_NE(-1, lseek(tf.fd, 0, SEEK_SET));
+
+  void* map = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, tf.fd, pagesize);
+  ASSERT_NE(MAP_FAILED, map);
+
+  char* data = reinterpret_cast<char*>(map);
+  ASSERT_STREQ(PAGE1_MSG, data);
+
+  ASSERT_EQ(0, munmap(map, pagesize));
+
+  map = mmap(NULL, pagesize, PROT_READ, MAP_SHARED, tf.fd, 2 * pagesize);
+  ASSERT_NE(MAP_FAILED, map);
+
+  data = reinterpret_cast<char*>(map);
+  ASSERT_STREQ(PAGE2_MSG, data);
+  ASSERT_STREQ(END_MSG, data+pagesize-sizeof(END_MSG));
+
+  ASSERT_EQ(0, munmap(map, pagesize));
+}
+
+#define NEWPAGE1_MSG "1NEW1PAGE1"
+#define NEWPAGE2_MSG "22NEW22PAGE22"
+
+TEST(sys_mman, mmap_file_write_at_offset) {
+  TemporaryFile tf;
+  size_t pagesize = sysconf(_SC_PAGESIZE);
+
+  // Create the file with three pages worth of data.
+  ASSERT_EQ(STR_SSIZE(PAGE0_MSG), write(tf.fd, PAGE0_MSG, sizeof(PAGE0_MSG)));
+  ASSERT_NE(-1, lseek(tf.fd, pagesize, SEEK_SET));
+  ASSERT_EQ(STR_SSIZE(PAGE1_MSG), write(tf.fd, PAGE1_MSG, sizeof(PAGE1_MSG)));
+  ASSERT_NE(-1, lseek(tf.fd, 2 * pagesize, SEEK_SET));
+  ASSERT_EQ(STR_SSIZE(PAGE2_MSG), write(tf.fd, PAGE2_MSG, sizeof(PAGE2_MSG)));
+  ASSERT_NE(-1, lseek(tf.fd, 3 * pagesize - sizeof(END_MSG), SEEK_SET));
+  ASSERT_EQ(STR_SSIZE(END_MSG), write(tf.fd, END_MSG, sizeof(END_MSG)));
+
+  ASSERT_NE(-1, lseek(tf.fd, 0, SEEK_SET));
+
+  void* map = mmap(NULL, pagesize, PROT_WRITE, MAP_SHARED, tf.fd, pagesize);
+  ASSERT_NE(MAP_FAILED, map);
+  close(tf.fd);
+
+  memcpy(map, NEWPAGE1_MSG, sizeof(NEWPAGE1_MSG));
+  ASSERT_EQ(0, munmap(map, pagesize));
+
+  tf.reopen();
+  map = mmap(NULL, pagesize, PROT_WRITE, MAP_SHARED, tf.fd, 2 * pagesize);
+  ASSERT_NE(MAP_FAILED, map);
+  close(tf.fd);
+
+  memcpy(map, NEWPAGE2_MSG, sizeof(NEWPAGE2_MSG));
+  ASSERT_EQ(0, munmap(map, pagesize));
+
+  tf.reopen();
+  char buf[pagesize];
+  ASSERT_EQ(static_cast<ssize_t>(pagesize), read(tf.fd, buf, pagesize));
+  ASSERT_STREQ(PAGE0_MSG, buf);
+  ASSERT_NE(-1, lseek(tf.fd, pagesize, SEEK_SET));
+  ASSERT_EQ(static_cast<ssize_t>(pagesize), read(tf.fd, buf, pagesize));
+  ASSERT_STREQ(NEWPAGE1_MSG, buf);
+  ASSERT_NE(-1, lseek(tf.fd, 2 * pagesize, SEEK_SET));
+  ASSERT_EQ(static_cast<ssize_t>(pagesize), read(tf.fd, buf, pagesize));
+  ASSERT_STREQ(NEWPAGE2_MSG, buf);
+  ASSERT_STREQ(END_MSG, buf+pagesize-sizeof(END_MSG));
 }