Merge "Improve detection of already loaded libraries"
diff --git a/libc/bionic/system_properties.cpp b/libc/bionic/system_properties.cpp
index ec3d04b..97e1a03 100644
--- a/libc/bionic/system_properties.cpp
+++ b/libc/bionic/system_properties.cpp
@@ -655,23 +655,6 @@
     return 0;
 }
 
-int __system_property_wait(const prop_info *pi)
-{
-    if (pi == 0) {
-        prop_area *pa = __system_property_area__;
-        const uint32_t n = pa->serial;
-        do {
-            __futex_wait(&pa->serial, n, NULL);
-        } while (n == pa->serial);
-    } else {
-        const uint32_t n = pi->serial;
-        do {
-            __futex_wait((volatile void *)&pi->serial, n, NULL);
-        } while (n == pi->serial);
-    }
-    return 0;
-}
-
 int __system_property_update(prop_info *pi, const char *value, unsigned int len)
 {
     prop_area *pa = __system_property_area__;
diff --git a/libc/include/pthread.h b/libc/include/pthread.h
index 7b8de81..49f943a 100644
--- a/libc/include/pthread.h
+++ b/libc/include/pthread.h
@@ -35,7 +35,7 @@
 #include <limits.h>
 #include <sys/types.h>
 
-#ifdef __LP64__
+#if defined(__LP64__)
   #define __RESERVED_INITIALIZER , {0}
 #else
   #define __RESERVED_INITIALIZER
@@ -112,7 +112,11 @@
 
 #define PTHREAD_ONCE_INIT 0
 
+#if defined(__LP64__)
+#define PTHREAD_STACK_MIN (4 * PAGE_SIZE)
+#else
 #define PTHREAD_STACK_MIN (2 * PAGE_SIZE)
+#endif
 
 #define PTHREAD_CREATE_DETACHED  0x00000001
 #define PTHREAD_CREATE_JOINABLE  0x00000000
diff --git a/libc/include/sys/ucontext.h b/libc/include/sys/ucontext.h
index 3737cbe..f150ac7 100644
--- a/libc/include/sys/ucontext.h
+++ b/libc/include/sys/ucontext.h
@@ -150,7 +150,8 @@
   stack_t uc_stack;
   mcontext_t uc_mcontext;
   sigset_t uc_sigmask;
-  /* TODO: __fpregs_mem? */
+  char __padding[128 - sizeof(sigset_t)];
+  struct _libc_fpstate __fpregs_mem;
 } ucontext_t;
 
 #elif defined(__mips__)
@@ -238,7 +239,31 @@
 typedef long greg_t;
 typedef greg_t gregset_t[NGREG];
 
-typedef struct user_i387_struct* fpregset_t;
+struct _libc_fpxreg {
+  unsigned short significand[4];
+  unsigned short exponent;
+  unsigned short padding[3];
+};
+
+struct _libc_xmmreg {
+  uint32_t element[4];
+};
+
+struct _libc_fpstate {
+  uint16_t cwd;
+  uint16_t swd;
+  uint16_t ftw;
+  uint16_t fop;
+  uint64_t rip;
+  uint64_t rdp;
+  uint32_t mxcsr;
+  uint32_t mxcr_mask;
+  struct _libc_fpxreg _st[8];
+  struct _libc_xmmreg _xmm[16];
+  uint32_t padding[24];
+};
+
+typedef struct _libc_fpstate* fpregset_t;
 
 typedef struct {
   gregset_t gregs;
@@ -252,7 +277,8 @@
   stack_t uc_stack;
   mcontext_t uc_mcontext;
   sigset_t uc_sigmask;
-  /* TODO: __fpregs_mem? */
+  char __padding[128 - sizeof(sigset_t)];
+  struct _libc_fpstate __fpregs_mem;
 } ucontext_t;
 
 #endif
diff --git a/libc/tzcode/localtime.c b/libc/tzcode/localtime.c
index 9f67dc6..c40569c 100644
--- a/libc/tzcode/localtime.c
+++ b/libc/tzcode/localtime.c
@@ -506,37 +506,41 @@
     if (doextend && nread > 2 &&
         up->buf[0] == '\n' && up->buf[nread - 1] == '\n' &&
         sp->typecnt + 2 <= TZ_MAX_TYPES) {
-            struct state ts;
+            struct state * ts = malloc(sizeof *ts);
             register int result;
 
+            if (ts == NULL)
+                goto oops;
+
             up->buf[nread - 1] = '\0';
-            result = tzparse(&up->buf[1], &ts, FALSE);
-            if (result == 0 && ts.typecnt == 2 &&
-                sp->charcnt + ts.charcnt <= TZ_MAX_CHARS) {
+            result = tzparse(&up->buf[1], ts, FALSE);
+            if (result == 0 && ts->typecnt == 2 &&
+                sp->charcnt + ts->charcnt <= TZ_MAX_CHARS) {
                     for (i = 0; i < 2; ++i)
-                        ts.ttis[i].tt_abbrind +=
+                        ts->ttis[i].tt_abbrind +=
                             sp->charcnt;
-                    for (i = 0; i < ts.charcnt; ++i)
+                    for (i = 0; i < ts->charcnt; ++i)
                         sp->chars[sp->charcnt++] =
-                            ts.chars[i];
+                            ts->chars[i];
                     i = 0;
-                    while (i < ts.timecnt &&
-                        ts.ats[i] <=
+                    while (i < ts->timecnt &&
+                        ts->ats[i] <=
                         sp->ats[sp->timecnt - 1])
                             ++i;
-                    while (i < ts.timecnt &&
+                    while (i < ts->timecnt &&
                         sp->timecnt < TZ_MAX_TIMES) {
                         sp->ats[sp->timecnt] =
-                            ts.ats[i];
+                            ts->ats[i];
                         sp->types[sp->timecnt] =
                             sp->typecnt +
-                            ts.types[i];
+                            ts->types[i];
                         ++sp->timecnt;
                         ++i;
                     }
-                    sp->ttis[sp->typecnt++] = ts.ttis[0];
-                    sp->ttis[sp->typecnt++] = ts.ttis[1];
+                    sp->ttis[sp->typecnt++] = ts->ttis[0];
+                    sp->ttis[sp->typecnt++] = ts->ttis[1];
             }
+            free(ts);
     }
     if (sp->timecnt > 1) {
         for (i = 1; i < sp->timecnt; ++i)
@@ -2280,22 +2284,33 @@
 
 // Non-standard API: mktime(3) but with an explicit timezone parameter.
 time_t mktime_tz(struct tm* const tmp, const char* tz) {
-  struct state st;
-  if (__bionic_tzload_cached(tz, &st, TRUE) != 0) {
+  struct state* st = malloc(sizeof(*st));
+  time_t return_value;
+
+  if (st == NULL)
+    return 0;
+  if (__bionic_tzload_cached(tz, st, TRUE) != 0) {
     // TODO: not sure what's best here, but for now, we fall back to gmt.
-    gmtload(&st);
+    gmtload(st);
   }
-  return time1(tmp, localsub, 0L, &st);
+
+  return_value = time1(tmp, localsub, 0L, st);
+  free(st);
+  return return_value;
 }
 
 // Non-standard API: localtime(3) but with an explicit timezone parameter.
 void localtime_tz(const time_t* const timep, struct tm* tmp, const char* tz) {
-  struct state st;
-  if (__bionic_tzload_cached(tz, &st, TRUE) != 0) {
+  struct state* st = malloc(sizeof(*st));
+
+  if (st == NULL)
+    return;
+  if (__bionic_tzload_cached(tz, st, TRUE) != 0) {
     // TODO: not sure what's best here, but for now, we fall back to gmt.
-    gmtload(&st);
+    gmtload(st);
   }
-  localsub(timep, 0L, tmp, &st);
+  localsub(timep, 0L, tmp, st);
+  free(st);
 }
 
 // END android-added
diff --git a/tests/stdio_test.cpp b/tests/stdio_test.cpp
index 2a0549a..4990582 100644
--- a/tests/stdio_test.cpp
+++ b/tests/stdio_test.cpp
@@ -17,6 +17,7 @@
 #include <gtest/gtest.h>
 
 #include <errno.h>
+#include <fcntl.h>
 #include <limits.h>
 #include <math.h>
 #include <stdio.h>
@@ -407,6 +408,28 @@
   EXPECT_STREQ("-0.000000", buf);
 }
 
+TEST(stdio, fprintf_failures_7229520) {
+  FILE* fp;
+
+  // Unbuffered case where the fprintf(3) itself fails.
+  ASSERT_NE(nullptr, fp = tmpfile());
+  setbuf(fp, NULL);
+  ASSERT_EQ(4, fprintf(fp, "epic"));
+  ASSERT_EQ(0, close(fileno(fp)));
+  ASSERT_EQ(-1, fprintf(fp, "fail"));
+  ASSERT_EQ(-1, fclose(fp));
+
+  // Buffered case where we won't notice until the fclose(3).
+  // It's likely this is what was actually seen in http://b/7229520,
+  // and that expecting fprintf to fail is setting yourself up for
+  // disappointment. Remember to check fclose(3)'s return value, kids!
+  ASSERT_NE(nullptr, fp = tmpfile());
+  ASSERT_EQ(4, fprintf(fp, "epic"));
+  ASSERT_EQ(0, close(fileno(fp)));
+  ASSERT_EQ(4, fprintf(fp, "fail"));
+  ASSERT_EQ(-1, fclose(fp));
+}
+
 TEST(stdio, popen) {
   FILE* fp = popen("cat /proc/version", "r");
   ASSERT_TRUE(fp != NULL);
@@ -560,9 +583,11 @@
   ASSERT_STREQ("C.UTF-8", setlocale(LC_CTYPE, "C.UTF-8"));
   uselocale(LC_GLOBAL_LOCALE);
 
-  // For glibc we need to close and re-open the file in order for fseek to work
-  // after using setlocale(LC_CTYPE, "C.UTF-8") and fputwc.
-  // TODO: find out if this is expected or a bug in glibc.
+  // In glibc-2.16 fseek doesn't work properly in wide mode
+  // (https://sourceware.org/bugzilla/show_bug.cgi?id=14543). One workaround is
+  // to close and re-open the file. We do it in order to make the test pass
+  // with all glibcs.
+
   TemporaryFile tf;
   FILE* fp = fdopen(tf.fd, "w+");
   ASSERT_TRUE(fp != NULL);