// This TZ value is not a valid Olson ID and is not present in tzdata file, // but is a valid TZ string according to POSIX standard.
setenv("TZ", "UTC+08:00:00", 1);
tzset();
ASSERT_EQ(static_cast<time_t>(8 * 60 * 60), mktime(&tm));
}
staticvoid* gmtime_no_stack_overflow_14313703_fn(void*) { constchar* original_tz = getenv("TZ"); // Ensure we'll actually have to enter tzload by using a timezone that doesn't exist.
setenv("TZ", "gmtime_stack_overflow_14313703", 1);
tzset(); if (original_tz != nullptr) {
setenv("TZ", original_tz, 1);
}
tzset(); return nullptr;
}
TEST(time, gmtime_no_stack_overflow_14313703) { // Is it safe to call tzload on a thread with a small stack? // http://b/14313703 // https://code.google.com/p/android/issues/detail?id=61130
pthread_attr_t a;
ASSERT_EQ(0, pthread_attr_init(&a));
ASSERT_EQ(0, pthread_attr_setstacksize(&a, PTHREAD_STACK_MIN));
#if !defined(__LP64__) // 32-bit bionic has a signed 32-bit time_t.
ASSERT_ERRNO_FAILURE(EOVERFLOW, -1, mktime(&tm)); #else // Everyone else should be using a signed 64-bit time_t.
ASSERT_GE(sizeof(time_t) * 8, 64U);
setenv("TZ", "America/Los_Angeles", 1);
tzset();
// On the date/time specified by tm America/Los_Angeles // follows DST. But tm_isdst is set to 0, which forces // mktime to interpret that time as local standard, hence offset // is 8 hours, not 7.
ASSERT_ERRNO_SUCCESS(0, static_cast<time_t>(4108348800U), mktime(&tm)); #endif
}
// This will overflow for LP32 or LP64. // tm_year is int, this t struct points to INT_MAX + 1 no matter what TZ is.
t.tm_year = INT_MAX;
t.tm_mon = 11;
t.tm_mday = 45;
struct tm t = {};
t.tm_year = 2022 - 1900;
t.tm_mon = 11;
t.tm_mday = 31; // UTC does not observe DST
t.tm_isdst = 1;
errno = 0;
// mktime sets errno to EOVERFLOW if result is unrepresentable.
EXPECT_ERRNO_FAILURE(EOVERFLOW, static_cast<time_t>(-1), mktime(&t));
}
// Transitions in the tzdata file are generated up to the year 2100. Testing // that dates beyond that are handled properly too.
TEST(time, mktime_after_2100) { struct tm tm = {.tm_year = 2150 - 1900, .tm_mon = 2, .tm_mday = 10, .tm_isdst = -1};
#if !defined(__LP64__) // 32-bit bionic has a signed 32-bit time_t.
ASSERT_ERRNO_FAILURE(EOVERFLOW, -1, mktime(&tm)); #else
setenv("TZ", "Europe/London", 1);
tzset();
ASSERT_ERRNO_SUCCESS(0, static_cast<time_t>(5686156800U), mktime(&tm)); #endif
}
TEST(time, strftime_Z_null_tm_zone) { // Netflix on Nexus Player wouldn't start (http://b/25170306). struct tm t = {}; char buf[64];
setenv("TZ", "America/Los_Angeles", 1);
tzset();
t.tm_isdst = 0; // "0 if Daylight Savings Time is not in effect".
EXPECT_EQ(5U, strftime(buf, sizeof(buf), "<%Z>", &t));
EXPECT_STREQ("<PST>", buf);
#ifdefined(__BIONIC__) // glibc 2.19 only copes with tm_isdst being 0 and 1.
t.tm_isdst = 2; // "positive if Daylight Savings Time is in effect"
EXPECT_EQ(5U, strftime(buf, sizeof(buf), "<%Z>", &t));
EXPECT_STREQ("<PDT>", buf);
t.tm_isdst = -123; // "and negative if the information is not available".
EXPECT_EQ(2U, strftime(buf, sizeof(buf), "<%Z>", &t));
EXPECT_STREQ("<>", buf); #endif
#ifdefined(__BIONIC__) // glibc 2.19 thinks UTC DST is "UTC".
t.tm_isdst = 1; // UTC has no DST.
EXPECT_EQ(2U, strftime(buf, sizeof(buf), "<%Z>", &t));
EXPECT_STREQ("<>", buf); #endif
}
// According to C language specification the only tm struct field needed to // find out replacement for %z and %Z in strftime is tm_isdst. Which is // wrong, as timezones change their standard offset and even DST savings. // tzcode deviates from C language specification and requires tm struct either // to be output of localtime-like functions or to be modified by mktime call // before passing to strftime. See tz mailing discussion for more details // https://mm.icann.org/pipermail/tz/2022-July/031674.html // But we are testing case when tm.tm_zone is null, which means that tm struct // is not coming from localtime and is neither modified by mktime. That's why // we are comparing against +0000, even though America/Los_Angeles never // observes it.
TEST(time, strftime_z_null_tm_zone) { char str[64]; struct tm tm = {.tm_year = 109, .tm_mon = 4, .tm_mday = 2, .tm_isdst = 0};
setenv("TZ", "America/Los_Angeles", 1);
tzset();
tm.tm_zone = NULL;
size_t result = strftime(str, sizeof(str), "%z", &tm);
TEST(time, strftime_z_Europe_Lisbon) { char str[64]; // During 1992-1996 Europe/Lisbon standard offset was 1 hour. // tm_isdst is not set as it will be overridden by mktime call anyway. struct tm tm = {.tm_year = 1996 - 1900, .tm_mon = 2, .tm_mday = 13};
setenv("TZ", "Europe/Lisbon", 1);
tzset();
// tzcode's strftime implementation for %z relies on prior mktime call. // At the moment of writing %z value is taken from tm_gmtoff. So without // mktime call %z is replaced with +0000. // See https://mm.icann.org/pipermail/tz/2022-July/031674.html
mktime(&tm);
size_t result = strftime(str, sizeof(str), "%z", &tm);
// INT32_MAX + 1 (aka overflow for ILP32). // This should be easy to detect because it'll be negative.
tm = {}; #ifdefined(__LP64__)
ASSERT_EQ('\0', *strptime("2147483648", "%s", &tm)); #else
ASSERT_EQ(nullptr, strptime("2147483648", "%s", &tm)); #endif
// This wraps to 1 as an int32_t.
tm = {}; #ifdefined(__LP64__)
ASSERT_EQ('\0', *strptime("4294967297", "%s", &tm));
EXPECT_EQ(206, tm.tm_year);
EXPECT_EQ(1, tm.tm_mon);
EXPECT_EQ(7, tm.tm_mday);
EXPECT_EQ(6, tm.tm_hour);
EXPECT_EQ(28, tm.tm_min);
EXPECT_EQ(17, tm.tm_sec); #else
ASSERT_EQ(nullptr, strptime("4294967297", "%s", &tm)); #endif
// INT64_MAX (aka "time_t max" for LP64). // This actually fails for LP64 too... // ...but in localtime_r() because the year is too large. // (Wolfram Alpha says this is 21 times the age of the universe!)
tm = {};
ASSERT_EQ(nullptr, strptime("9223372036854775807", "%s", &tm));
}
// %V (ISO-8601 week number), %G (year of week number, without century), and // %g (year of week number) have no effect when parsed, and are supported // solely so that it's possible for strptime(3) to parse everything that // strftime(3) can output. struct tm tm = {};
ASSERT_EQ('\0', *strptime("1 2 3", "%V %G %g", &tm)); struct tm zero = {};
EXPECT_TRUE(memcmp(&tm, &zero, sizeof(tm)) == 0);
}
TEST(time, strptime_Z) { #ifdefined(__BIONIC__) // glibc doesn't handle %Z at all. // The BSDs only handle hard-coded "GMT" and "UTC", plus whatever two strings // are in the global `tzname` (which correspond to the current $TZ). struct tm tm;
setenv("TZ", "Europe/Berlin", 1);
// As does "UTC".
tm = {};
ASSERT_EQ('\0', *strptime("UTC", "%Z", &tm));
EXPECT_STREQ("UTC", tm.tm_zone);
EXPECT_EQ(0, tm.tm_isdst);
EXPECT_EQ(0, tm.tm_gmtoff);
// Europe/Berlin is known as "CET" when there's no DST.
tm = {};
ASSERT_EQ('\0', *strptime("CET", "%Z", &tm));
EXPECT_STREQ("CET", tm.tm_zone);
EXPECT_EQ(0, tm.tm_isdst);
EXPECT_EQ(3600, tm.tm_gmtoff);
// Europe/Berlin is known as "CEST" when there's no DST.
tm = {};
ASSERT_EQ('\0', *strptime("CEST", "%Z", &tm));
EXPECT_STREQ("CEST", tm.tm_zone);
EXPECT_EQ(1, tm.tm_isdst);
EXPECT_EQ(3600, tm.tm_gmtoff);
// And as long as we're in Europe/Berlin, those are the only timezone // abbreviations that are recognized.
tm = {};
ASSERT_TRUE(strptime("PDT", "%Z", &tm) == nullptr); #endif
}
// "UT" is what RFC822 called UTC.
tm = {};
ASSERT_EQ('\0', *strptime("UT", "%z", &tm));
EXPECT_STREQ("UTC", tm.tm_zone);
EXPECT_EQ(0, tm.tm_isdst);
EXPECT_EQ(0, tm.tm_gmtoff); // "GMT" is RFC822's other name for UTC.
tm = {};
ASSERT_EQ('\0', *strptime("GMT", "%z", &tm));
EXPECT_STREQ("UTC", tm.tm_zone);
EXPECT_EQ(0, tm.tm_isdst);
EXPECT_EQ(0, tm.tm_gmtoff);
// "Z" ("Zulu") is a synonym for UTC.
tm = {};
ASSERT_EQ('\0', *strptime("Z", "%z", &tm));
EXPECT_STREQ("UTC", tm.tm_zone);
EXPECT_EQ(0, tm.tm_isdst);
EXPECT_EQ(0, tm.tm_gmtoff);
// "PST"/"PDT" and the other common US zone abbreviations are all supported.
tm = {};
ASSERT_EQ('\0', *strptime("PST", "%z", &tm));
EXPECT_STREQ("PST", tm.tm_zone);
EXPECT_EQ(0, tm.tm_isdst);
EXPECT_EQ(-28800, tm.tm_gmtoff);
tm = {};
ASSERT_EQ('\0', *strptime("PDT", "%z", &tm));
EXPECT_STREQ("PDT", tm.tm_zone);
EXPECT_EQ(1, tm.tm_isdst);
EXPECT_EQ(-25200, tm.tm_gmtoff);
counter.SetTime(0, 1, 0, 10);
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
ASSERT_TRUE(counter.ValueUpdated());
counter.DeleteTimer(); // Add a sleep as other threads may be calling the callback function when the timer is deleted.
usleep(500000);
}
TEST(time, timer_create_NULL) { // A NULL sigevent* is equivalent to asking for SIGEV_SIGNAL for SIGALRM.
timer_t timer_id;
ASSERT_EQ(0, timer_create(CLOCK_MONOTONIC, nullptr, &timer_id));
// A SIGEV_SIGNAL timer failure is easy; that's the kernel's problem.
timer_t timer_id;
ASSERT_ERRNO_FAILURE(EINVAL, -1, timer_create(kInvalidClock, nullptr, &timer_id));
// A SIGEV_THREAD timer failure is more interesting because we have a thread // to clean up (https://issuetracker.google.com/340125671).
sigevent se = {};
se.sigev_notify = SIGEV_THREAD;
se.sigev_notify_function = NoOpNotifyFunction;
ASSERT_ERRNO_FAILURE(EINVAL, -1, timer_create(kInvalidClock, &se, &timer_id));
// timer_create() doesn't guarantee that the thread will be dead _before_ // it returns because that would require extra synchronization that's // unnecessary in the normal (successful) case. A timeout here means we // leaked a thread. while (GetThreadCount() > 1) {
}
}
// Test to verify that disarming a repeatable timer disables the callbacks.
TEST(time, timer_disarm_terminates) {
Counter counter(Counter::CountNotifyFunction);
ASSERT_EQ(0, counter.Value());
counter.SetTime(0, 0, 0, 0); // Add a sleep as the kernel may have pending events when the timer is disarmed.
usleep(500000); int value = counter.Value();
usleep(500000);
// Verify the counter has not been incremented.
ASSERT_EQ(value, counter.Value());
}
// Test to verify that deleting a repeatable timer disables the callbacks.
TEST(time, timer_delete_terminates) {
Counter counter(Counter::CountNotifyFunction);
ASSERT_EQ(0, counter.Value());
counter.DeleteTimer(); // Add a sleep as other threads may be calling the callback function when the timer is deleted.
usleep(500000); int value = counter.Value();
usleep(500000);
// Verify the counter has not been incremented.
ASSERT_EQ(value, counter.Value());
}
TEST(time, clock) { // clock(3) is hard to test, but a 1s sleep should cost less than 10ms on average. staticconst clock_t N = 5; staticconst clock_t mean_limit_ms = 10;
clock_t t0 = clock(); for (size_t i = 0; i < N; ++i) {
sleep(1);
}
clock_t t1 = clock();
ASSERT_LT(t1 - t0, N * mean_limit_ms * (CLOCKS_PER_SEC / 1000));
}
TEST(time, clock_getcpuclockid_ESRCH) { // We can't use -1 for invalid pid here, because clock_getcpuclockid() can't detect it.
errno = 0; // If this fails, your kernel needs commit e1b6b6ce to be backported.
clockid_t clockid;
ASSERT_EQ(ESRCH, clock_getcpuclockid(GetInvalidPid(), &clockid)) << "\n"
<< "Please ensure that the following kernel patches or their replacements have been applied:\n"
<< "* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/"
<< "commit/?id=e1b6b6ce55a0a25c8aa8af019095253b2133a41a\n"
<< "* https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/"
<< "commit/?id=c80ed088a519da53f27b798a69748eaabc66aadf\n";
ASSERT_ERRNO(0);
}
// Actual underlying bug (the code change, not the tzdata upgrade that first exposed the bug): // http://b/31848040
// This isn't a great test, because very few timezones were actually affected, and there's // no real logic to which ones were affected: it was just a coincidence of the data that came // after them in the tzdata file.
TEST(time, bug_31339449) { // POSIX says localtime acts as if it calls tzset. // tzset does two things: // 1. it sets the timezone ctime/localtime/mktime/strftime will use. // 2. it sets the global `tzname`. // POSIX says localtime_r need not set `tzname` (2). // Q: should localtime_r set the timezone (1)? // Upstream tzcode (and glibc) answer "no", everyone else answers "yes".
// Pick a time, any time...
time_t t = 1475619727;
// Call tzset with a specific timezone.
setenv("TZ", "America/Atka", 1);
tzset();
// If we change the timezone and call localtime, localtime should use the new timezone.
setenv("TZ", "America/Los_Angeles", 1); struct tm* tm_p = localtime(&t);
EXPECT_EQ(15, tm_p->tm_hour);
// Reset the timezone back.
setenv("TZ", "America/Atka", 1);
tzset();
#ifdefined(__BIONIC__) // If we change the timezone again and call localtime_r, localtime_r should use the new timezone.
setenv("TZ", "America/Los_Angeles", 1); struct tm tm = {};
localtime_r(&t, &tm);
EXPECT_EQ(15, tm.tm_hour); #else // The BSDs agree with us, but glibc gets this wrong. #endif
}
TEST(time, tzalloc_nullptr) { #ifdefined(__BIONIC__) // tzalloc(nullptr) returns the system timezone.
timezone_t default_tz = tzalloc(nullptr);
ASSERT_NE(nullptr, default_tz);
// Check that mktime_z() with the default timezone matches mktime(). // This assumes that the system timezone doesn't change during the test, // but that should be unlikely, and we don't have much choice if we // want to write a test at all. // We unset $TZ before calling mktime() because mktime() honors $TZ.
unsetenv("TZ"); struct tm tm = {.tm_year = 93, .tm_mday = 1};
time_t t = mktime(&tm);
ASSERT_EQ(t, mktime_z(default_tz, &tm));
// Check that changing $TZ doesn't affect the tzalloc() default in // the same way it would the mktime() default.
setenv("TZ", "America/Los_Angeles", 1);
tzset();
ASSERT_EQ(t, mktime_z(default_tz, &tm));
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.