Merge "Allow wildcards to match arg values."
diff --git a/libc/bionic/ndk_cruft.cpp b/libc/bionic/ndk_cruft.cpp
index ceff6a1..109c523 100644
--- a/libc/bionic/ndk_cruft.cpp
+++ b/libc/bionic/ndk_cruft.cpp
@@ -358,3 +358,6 @@
 
 // This is never implemented in bionic, only needed for ABI compatibility with the NDK.
 extern "C" void endusershell() { }
+
+// This is never implemented in bionic, only needed for ABI compatibility with the NDK.
+extern "C" void endpwent() { }
diff --git a/libc/bionic/stubs.cpp b/libc/bionic/stubs.cpp
index c192bf8..f9a31b9 100644
--- a/libc/bionic/stubs.cpp
+++ b/libc/bionic/stubs.cpp
@@ -446,18 +446,6 @@
   return NULL;
 }
 
-static void unimplemented_stub(const char* function) {
-  const char* fmt = "%s(3) is not implemented on Android\n";
-  __libc_format_log(ANDROID_LOG_WARN, "libc", fmt, function);
-  fprintf(stderr, fmt, function);
-}
-
-#define UNIMPLEMENTED unimplemented_stub(__PRETTY_FUNCTION__)
-
-void endpwent() {
-  UNIMPLEMENTED;
-}
-
 // Portable code should use sysconf(_SC_PAGE_SIZE) directly instead.
 int getpagesize() {
   // We dont use sysconf(3) here because that drags in stdio, which makes static binaries fat.
diff --git a/libc/bionic/system_properties.cpp b/libc/bionic/system_properties.cpp
index 170e7ac..aae99b1 100644
--- a/libc/bionic/system_properties.cpp
+++ b/libc/bionic/system_properties.cpp
@@ -51,7 +51,6 @@
 #include <sys/_system_properties.h>
 #include <sys/system_properties.h>
 
-#include "private/bionic_atomic_inline.h"
 #include "private/bionic_futex.h"
 #include "private/bionic_macros.h"
 
@@ -80,22 +79,26 @@
     uint8_t namelen;
     uint8_t reserved[3];
 
-    // TODO: The following fields should be declared as atomic_uint32_t.
-    // They should be assigned to with release semantics, instead of using
-    // explicit fences.  Unfortunately, the read accesses are generally
-    // followed by more dependent read accesses, and the dependence
-    // is assumed to enforce memory ordering.  Which it does on supported
-    // hardware.  This technically should use memory_order_consume, if
-    // that worked as intended.
+    // The property trie is updated only by the init process (single threaded) which provides
+    // property service. And it can be read by multiple threads at the same time.
+    // As the property trie is not protected by locks, we use atomic_uint_least32_t types for the
+    // left, right, children "pointers" in the trie node. To make sure readers who see the
+    // change of "pointers" can also notice the change of prop_bt structure contents pointed by
+    // the "pointers", we always use release-consume ordering pair when accessing these "pointers".
+
+    // prop "points" to prop_info structure if there is a propery associated with the trie node.
+    // Its situation is similar to the left, right, children "pointers". So we use
+    // atomic_uint_least32_t and release-consume ordering to protect it as well.
+
     // We should also avoid rereading these fields redundantly, since not
     // all processor implementations ensure that multiple loads from the
     // same field are carried out in the right order.
-    volatile uint32_t prop;
+    atomic_uint_least32_t prop;
 
-    volatile uint32_t left;
-    volatile uint32_t right;
+    atomic_uint_least32_t left;
+    atomic_uint_least32_t right;
 
-    volatile uint32_t children;
+    atomic_uint_least32_t children;
 
     char name[0];
 
@@ -103,8 +106,6 @@
         this->namelen = name_length;
         memcpy(this->name, name, name_length);
         this->name[name_length] = '\0';
-        ANDROID_MEMBAR_FULL();  // TODO: Instead use a release store
-                                // for subsequent pointer assignment.
     }
 
 private:
@@ -143,8 +144,6 @@
         atomic_init(&this->serial, valuelen << 24);
         memcpy(this->value, value, valuelen);
         this->value[valuelen] = '\0';
-        ANDROID_MEMBAR_FULL();  // TODO: Instead use a release store
-                                // for subsequent point assignment.
     }
 private:
     DISALLOW_COPY_AND_ASSIGN(prop_info);
@@ -291,10 +290,10 @@
     return map_result;
 }
 
-static void *allocate_obj(const size_t size, uint32_t *const off)
+static void *allocate_obj(const size_t size, uint_least32_t *const off)
 {
     prop_area *pa = __system_property_area__;
-    const size_t aligned = BIONIC_ALIGN(size, sizeof(uint32_t));
+    const size_t aligned = BIONIC_ALIGN(size, sizeof(uint_least32_t));
     if (pa->bytes_used + aligned > pa_data_size) {
         return NULL;
     }
@@ -304,12 +303,12 @@
     return pa->data + *off;
 }
 
-static prop_bt *new_prop_bt(const char *name, uint8_t namelen, uint32_t *const off)
+static prop_bt *new_prop_bt(const char *name, uint8_t namelen, uint_least32_t *const off)
 {
-    uint32_t new_offset;
-    void *const offset = allocate_obj(sizeof(prop_bt) + namelen + 1, &new_offset);
-    if (offset) {
-        prop_bt* bt = new(offset) prop_bt(name, namelen);
+    uint_least32_t new_offset;
+    void *const p = allocate_obj(sizeof(prop_bt) + namelen + 1, &new_offset);
+    if (p != NULL) {
+        prop_bt* bt = new(p) prop_bt(name, namelen);
         *off = new_offset;
         return bt;
     }
@@ -318,20 +317,20 @@
 }
 
 static prop_info *new_prop_info(const char *name, uint8_t namelen,
-        const char *value, uint8_t valuelen, uint32_t *const off)
+        const char *value, uint8_t valuelen, uint_least32_t *const off)
 {
-    uint32_t off_tmp;
-    void* const offset = allocate_obj(sizeof(prop_info) + namelen + 1, &off_tmp);
-    if (offset) {
-        prop_info* info = new(offset) prop_info(name, namelen, value, valuelen);
-        *off = off_tmp;
+    uint_least32_t new_offset;
+    void* const p = allocate_obj(sizeof(prop_info) + namelen + 1, &new_offset);
+    if (p != NULL) {
+        prop_info* info = new(p) prop_info(name, namelen, value, valuelen);
+        *off = new_offset;
         return info;
     }
 
     return NULL;
 }
 
-static void *to_prop_obj(const uint32_t off)
+static void *to_prop_obj(uint_least32_t off)
 {
     if (off > pa_data_size)
         return NULL;
@@ -341,7 +340,17 @@
     return (__system_property_area__->data + off);
 }
 
-static prop_bt *root_node()
+static inline prop_bt *to_prop_bt(atomic_uint_least32_t* off_p) {
+  uint_least32_t off = atomic_load_explicit(off_p, memory_order_consume);
+  return reinterpret_cast<prop_bt*>(to_prop_obj(off));
+}
+
+static inline prop_info *to_prop_info(atomic_uint_least32_t* off_p) {
+  uint_least32_t off = atomic_load_explicit(off_p, memory_order_consume);
+  return reinterpret_cast<prop_info*>(to_prop_obj(off));
+}
+
+static inline prop_bt *root_node()
 {
     return reinterpret_cast<prop_bt*>(to_prop_obj(0));
 }
@@ -373,36 +382,34 @@
         }
 
         if (ret < 0) {
-            if (current->left) {
-                current = reinterpret_cast<prop_bt*>(to_prop_obj(current->left));
+            uint_least32_t left_offset = atomic_load_explicit(&current->left, memory_order_relaxed);
+            if (left_offset != 0) {
+                current = to_prop_bt(&current->left);
             } else {
                 if (!alloc_if_needed) {
                    return NULL;
                 }
 
-                // Note that there isn't a race condition here. "clients" never
-                // reach this code-path since It's only the (single threaded) server
-                // that allocates new nodes. Though "bt->left" is volatile, it can't
-                // have changed since the last value was last read.
-                uint32_t new_offset = 0;
+                uint_least32_t new_offset;
                 prop_bt* new_bt = new_prop_bt(name, namelen, &new_offset);
                 if (new_bt) {
-                    current->left = new_offset;
+                    atomic_store_explicit(&current->left, new_offset, memory_order_release);
                 }
                 return new_bt;
             }
         } else {
-            if (current->right) {
-                current = reinterpret_cast<prop_bt*>(to_prop_obj(current->right));
+            uint_least32_t right_offset = atomic_load_explicit(&current->right, memory_order_relaxed);
+            if (right_offset != 0) {
+                current = to_prop_bt(&current->right);
             } else {
                 if (!alloc_if_needed) {
                    return NULL;
                 }
 
-                uint32_t new_offset;
+                uint_least32_t new_offset;
                 prop_bt* new_bt = new_prop_bt(name, namelen, &new_offset);
                 if (new_bt) {
-                    current->right = new_offset;
+                    atomic_store_explicit(&current->right, new_offset, memory_order_release);
                 }
                 return new_bt;
             }
@@ -429,13 +436,14 @@
         }
 
         prop_bt* root = NULL;
-        if (current->children) {
-            root = reinterpret_cast<prop_bt*>(to_prop_obj(current->children));
+        uint_least32_t children_offset = atomic_load_explicit(&current->children, memory_order_relaxed);
+        if (children_offset != 0) {
+            root = to_prop_bt(&current->children);
         } else if (alloc_if_needed) {
-            uint32_t new_bt_offset;
-            root = new_prop_bt(remaining_name, substr_size, &new_bt_offset);
+            uint_least32_t new_offset;
+            root = new_prop_bt(remaining_name, substr_size, &new_offset);
             if (root) {
-                current->children = new_bt_offset;
+                atomic_store_explicit(&current->children, new_offset, memory_order_release);
             }
         }
 
@@ -454,13 +462,14 @@
         remaining_name = sep + 1;
     }
 
-    if (current->prop) {
-        return reinterpret_cast<prop_info*>(to_prop_obj(current->prop));
+    uint_least32_t prop_offset = atomic_load_explicit(&current->prop, memory_order_relaxed);
+    if (prop_offset != 0) {
+        return to_prop_info(&current->prop);
     } else if (alloc_if_needed) {
-        uint32_t new_info_offset;
-        prop_info* new_info = new_prop_info(name, namelen, value, valuelen, &new_info_offset);
+        uint_least32_t new_offset;
+        prop_info* new_info = new_prop_info(name, namelen, value, valuelen, &new_offset);
         if (new_info) {
-            current->prop = new_info_offset;
+            atomic_store_explicit(&current->prop, new_offset, memory_order_release);
         }
 
         return new_info;
@@ -534,31 +543,34 @@
     cookie->count++;
 }
 
-static int foreach_property(const uint32_t off,
+static int foreach_property(prop_bt *const trie,
         void (*propfn)(const prop_info *pi, void *cookie), void *cookie)
 {
-    prop_bt *trie = reinterpret_cast<prop_bt*>(to_prop_obj(off));
     if (!trie)
         return -1;
 
-    if (trie->left) {
-        const int err = foreach_property(trie->left, propfn, cookie);
+    uint_least32_t left_offset = atomic_load_explicit(&trie->left, memory_order_relaxed);
+    if (left_offset != 0) {
+        const int err = foreach_property(to_prop_bt(&trie->left), propfn, cookie);
         if (err < 0)
             return -1;
     }
-    if (trie->prop) {
-        prop_info *info = reinterpret_cast<prop_info*>(to_prop_obj(trie->prop));
+    uint_least32_t prop_offset = atomic_load_explicit(&trie->prop, memory_order_relaxed);
+    if (prop_offset != 0) {
+        prop_info *info = to_prop_info(&trie->prop);
         if (!info)
             return -1;
         propfn(info, cookie);
     }
-    if (trie->children) {
-        const int err = foreach_property(trie->children, propfn, cookie);
+    uint_least32_t children_offset = atomic_load_explicit(&trie->children, memory_order_relaxed);
+    if (children_offset != 0) {
+        const int err = foreach_property(to_prop_bt(&trie->children), propfn, cookie);
         if (err < 0)
             return -1;
     }
-    if (trie->right) {
-        const int err = foreach_property(trie->right, propfn, cookie);
+    uint_least32_t right_offset = atomic_load_explicit(&trie->right, memory_order_relaxed);
+    if (right_offset != 0) {
+        const int err = foreach_property(to_prop_bt(&trie->right), propfn, cookie);
         if (err < 0)
             return -1;
     }
@@ -766,5 +778,5 @@
         return __system_property_foreach_compat(propfn, cookie);
     }
 
-    return foreach_property(0, propfn, cookie);
+    return foreach_property(root_node(), propfn, cookie);
 }
diff --git a/libc/include/grp.h b/libc/include/grp.h
index 7b3e32b..df7a613 100644
--- a/libc/include/grp.h
+++ b/libc/include/grp.h
@@ -54,9 +54,9 @@
 struct group	*getgrgid(gid_t);
 struct group	*getgrnam(const char *);
 #if __POSIX_VISIBLE >= 200112 || __XPG_VISIBLE
-struct group	*getgrent(void) __errorattr("getgrent is meaningless on Android");
-__errordecl(setgrent, "setgrent is meaningless on Android");
-__errordecl(endgrent, "endgrent is meaningless on Android");
+struct group	*getgrent(void)  __attribute__((deprecated("getgrent is meaningless on Android")));
+void setgrent(void) __attribute__((deprecated("setgrent is meaningless on Android")));
+void endgrent(void) __attribute__((deprecated("endgrent is meaningless on Android")));
 int		 getgrgid_r(gid_t, struct group *, char *,
 		    size_t, struct group **);
 int		 getgrnam_r(const char *, struct group *, char *,
diff --git a/libc/include/pwd.h b/libc/include/pwd.h
index 6d483c0..6012b96 100644
--- a/libc/include/pwd.h
+++ b/libc/include/pwd.h
@@ -119,10 +119,6 @@
 int getpwnam_r(const char*, struct passwd*, char*, size_t, struct passwd**);
 int getpwuid_r(uid_t, struct passwd*, char*, size_t, struct passwd**);
 
-void endpwent(void);
-struct passwd* getpwent(void);
-int setpwent(void);
-
 __END_DECLS
 
 #endif
diff --git a/libc/include/stdio.h b/libc/include/stdio.h
index 17ef096..f5ed652 100644
--- a/libc/include/stdio.h
+++ b/libc/include/stdio.h
@@ -264,16 +264,16 @@
 
 #ifndef __AUDIT__
 #if !defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112L
-char* gets(char*) __attribute__((deprecated("gets is very unsafe; consider using fgets")));
+char* gets(char*) __attribute__((deprecated("gets is unsafe, use fgets instead")));
 #endif
 int sprintf(char* __restrict, const char* __restrict, ...)
     __printflike(2, 3) __warnattr("sprintf is often misused; please use snprintf");
-char* tmpnam(char*) __warnattr("tmpnam possibly used unsafely; consider using mkstemp");
 int vsprintf(char* __restrict, const char* __restrict, __va_list)
     __printflike(2, 0) __warnattr("vsprintf is often misused; please use vsnprintf");
+char* tmpnam(char*) __attribute__((deprecated("tmpnam is unsafe, use mkstemp or tmpfile instead")));
 #if __XPG_VISIBLE
 char* tempnam(const char*, const char*)
-    __warnattr("tempnam possibly used unsafely; consider using mkstemp");
+    __attribute__((deprecated("tempnam is unsafe, use mkstemp or tmpfile instead")));
 #endif
 #endif
 
diff --git a/libc/include/stdlib.h b/libc/include/stdlib.h
index cbd7aeb..84bf56d 100644
--- a/libc/include/stdlib.h
+++ b/libc/include/stdlib.h
@@ -58,7 +58,7 @@
 extern int clearenv(void);
 
 extern char* mkdtemp(char*);
-extern char* mktemp(char*) __warnattr("mktemp possibly used unsafely; consider using mkstemp");
+extern char* mktemp(char*) __attribute__((deprecated("mktemp is unsafe, use mkstemp or tmpfile instead")));
 
 extern int mkostemp64(char*, int);
 extern int mkostemp(char*, int);