Merge "fix shared gid support in getpwnam/getgrnam"
diff --git a/libc/tzcode/localtime.c b/libc/tzcode/localtime.c
index 28d13f4..29f605c 100644
--- a/libc/tzcode/localtime.c
+++ b/libc/tzcode/localtime.c
@@ -1257,6 +1257,7 @@
lclptr->ttis[0].tt_gmtoff = 0;
lclptr->ttis[0].tt_abbrind = 0;
(void) strcpy(lclptr->chars, gmt);
+ lclptr->defaulttype = 0;
} else if (tzload(name, lclptr, TRUE) != 0)
if (name[0] == ':' || tzparse(name, lclptr, FALSE) != 0)
(void) gmtload(lclptr);
diff --git a/linker/linker.cpp b/linker/linker.cpp
index 11d7b94..1d68db5 100644
--- a/linker/linker.cpp
+++ b/linker/linker.cpp
@@ -1135,28 +1135,27 @@
return si;
}
-static void soinfo_unload(soinfo* si) {
+static void soinfo_unload_schedule(soinfo::soinfo_list_t& unload_list, soinfo* si) {
if (!si->can_unload()) {
TRACE("not unloading '%s' - the binary is flagged with NODELETE", si->name);
return;
}
if (si->ref_count == 1) {
- TRACE("unloading '%s'", si->name);
- si->call_destructors();
+ unload_list.push_back(si);
if (si->has_min_version(0)) {
soinfo* child = nullptr;
while ((child = si->get_children().pop_front()) != nullptr) {
TRACE("%s needs to unload %s", si->name, child->name);
- soinfo_unload(child);
+ soinfo_unload_schedule(unload_list, child);
}
} else {
for_each_dt_needed(si, [&] (const char* library_name) {
TRACE("deprecated (old format of soinfo): %s needs to unload %s", si->name, library_name);
soinfo* needed = find_library(library_name, RTLD_NOLOAD, nullptr);
if (needed != nullptr) {
- soinfo_unload(needed);
+ soinfo_unload_schedule(unload_list, needed);
} else {
// Not found: for example if symlink was deleted between dlopen and dlclose
// Since we cannot really handle errors at this point - print and continue.
@@ -1165,15 +1164,28 @@
});
}
- notify_gdb_of_unload(si);
si->ref_count = 0;
- soinfo_free(si);
} else {
si->ref_count--;
TRACE("not unloading '%s', decrementing ref_count to %zd", si->name, si->ref_count);
}
}
+static void soinfo_unload(soinfo* root) {
+ soinfo::soinfo_list_t unload_list;
+ soinfo_unload_schedule(unload_list, root);
+ unload_list.for_each([](soinfo* si) {
+ si->call_destructors();
+ });
+
+ soinfo* si = nullptr;
+ while ((si = unload_list.pop_front()) != nullptr) {
+ TRACE("unloading '%s'", si->name);
+ notify_gdb_of_unload(si);
+ soinfo_free(si);
+ }
+}
+
void do_android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size) {
// Use basic string manipulation calls to avoid snprintf.
// snprintf indirectly calls pthread_getspecific to get the size of a buffer.
diff --git a/tests/libs/dlopen_check_order_reloc_nephew_answer.cpp b/tests/libs/dlopen_check_order_reloc_nephew_answer.cpp
index 065d1be..d6d1f09 100644
--- a/tests/libs/dlopen_check_order_reloc_nephew_answer.cpp
+++ b/tests/libs/dlopen_check_order_reloc_nephew_answer.cpp
@@ -19,3 +19,19 @@
extern "C" int check_order_reloc_nephew_get_answer() {
return check_order_reloc_get_answer_impl();
}
+
+namespace {
+// The d-tor for this class is called on dlclose() -> __on_dlclose() -> __cxa_finalize()
+// We use it to detect calls to prematurely unmapped libraries during dlclose.
+// See also b/18338888
+class CallNephewInDtor {
+ public:
+ ~CallNephewInDtor() {
+ check_order_reloc_get_answer_impl();
+ }
+} instance;
+};
+
+extern "C" void* get_instance() {
+ return &instance;
+}
diff --git a/tests/time_test.cpp b/tests/time_test.cpp
index 7a551b4..e0231b1 100644
--- a/tests/time_test.cpp
+++ b/tests/time_test.cpp
@@ -71,6 +71,30 @@
ASSERT_EQ(0, pthread_join(t, &result));
}
+TEST(time, mktime_empty_TZ) {
+ // tzcode used to have a bug where it didn't reinitialize some internal state.
+
+ // Choose a time where DST is set.
+ struct tm t;
+ memset(&t, 0, sizeof(tm));
+ t.tm_year = 1980 - 1900;
+ t.tm_mon = 6;
+ t.tm_mday = 2;
+
+ setenv("TZ", "America/Los_Angeles", 1);
+ tzset();
+ ASSERT_EQ(static_cast<time_t>(331372800U), mktime(&t));
+
+ memset(&t, 0, sizeof(tm));
+ t.tm_year = 1980 - 1900;
+ t.tm_mon = 6;
+ t.tm_mday = 2;
+
+ setenv("TZ", "", 1); // Implies UTC.
+ tzset();
+ ASSERT_EQ(static_cast<time_t>(331344000U), mktime(&t));
+}
+
TEST(time, mktime_10310929) {
struct tm t;
memset(&t, 0, sizeof(tm));