OSDN Git Service

Fix tzdata loading.
authorElliott Hughes <enh@google.com>
Mon, 3 Oct 2016 19:29:30 +0000 (12:29 -0700)
committerElliott Hughes <enh@google.com>
Mon, 3 Oct 2016 19:45:13 +0000 (12:45 -0700)
Android uses one large file of tzdata, so the "read up to the maximum
possible length of a valid tzfile" code in upstream localtime.c is
broken: there is always data after the current tzfile (even the
last tzfile is followed by the zone.tab data). This patch passes the
exact length through to the read(2) call so we don't over-read, rather
than have to rewrite upstream code that measures back from the "end" of
the tzfile.

The old code failed the existing time.strftime_null_tm_zone test after
updating to tzdata2016g.

Bug: http://b/31848040
Test: time.strftime_null_tm_zone
Change-Id: Iee059b5a8c051bd4952cfd80f02b00d83e489d5e

libc/tzcode/localtime.c

index adc2f1b..6e88819 100644 (file)
@@ -369,7 +369,7 @@ union local_storage {
   } u;
 };
 
-static int __bionic_open_tzdata(const char*);
+static int __bionic_open_tzdata(const char*, int32_t*);
 
 /* Load tz data from the file named NAME into *SP.  Read extended
    format if DOEXTEND.  Use *LSP for temporary storage.  Return 0 on
@@ -398,7 +398,8 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
        }
 
 #if defined(__BIONIC__)
-       fid = __bionic_open_tzdata(name);
+       int32_t entry_length;
+       fid = __bionic_open_tzdata(name, &entry_length);
 #else
        if (name[0] == ':')
                ++name;
@@ -424,7 +425,11 @@ tzloadbody(char const *name, struct state *sp, bool doextend,
        if (fid < 0)
          return errno;
 
+#if defined(__BIONIC__)
+       nread = read(fid, up->buf, entry_length);
+#else
        nread = read(fid, up->buf, sizeof up->buf);
+#endif
        if (nread < tzheadsize) {
          int err = nread < 0 ? errno : EINVAL;
          close(fid);
@@ -2342,7 +2347,8 @@ time(time_t *p)
 #include <arpa/inet.h> // For ntohl(3).
 
 static int __bionic_open_tzdata_path(const char* path_prefix_variable, const char* path_suffix,
-                                     const char* olson_id) {
+                                     const char* olson_id,
+                                     int32_t* entry_length) {
   const char* path_prefix = getenv(path_prefix_variable);
   if (path_prefix == NULL) {
     fprintf(stderr, "%s: %s not set!\n", __FUNCTION__, path_prefix_variable);
@@ -2440,6 +2446,7 @@ static int __bionic_open_tzdata_path(const char* path_prefix_variable, const cha
 
     if (strcmp(this_id, olson_id) == 0) {
       specific_zone_offset = ntohl(entry->start) + ntohl(header.data_offset);
+      *entry_length = ntohl(entry->length);
       break;
     }
 
@@ -2467,10 +2474,12 @@ static int __bionic_open_tzdata_path(const char* path_prefix_variable, const cha
   return fd;
 }
 
-static int __bionic_open_tzdata(const char* olson_id) {
-  int fd = __bionic_open_tzdata_path("ANDROID_DATA", "/misc/zoneinfo/current/tzdata", olson_id);
+static int __bionic_open_tzdata(const char* olson_id, int32_t* entry_length) {
+  int fd = __bionic_open_tzdata_path("ANDROID_DATA", "/misc/zoneinfo/current/tzdata",
+                                     olson_id, entry_length);
   if (fd < 0) {
-    fd = __bionic_open_tzdata_path("ANDROID_ROOT", "/usr/share/zoneinfo/tzdata", olson_id);
+    fd = __bionic_open_tzdata_path("ANDROID_ROOT", "/usr/share/zoneinfo/tzdata",
+                                   olson_id, entry_length);
     if (fd == -2) {
       // The first thing that 'recovery' does is try to format the current time. It doesn't have
       // any tzdata available, so we must not abort here --- doing so breaks the recovery image!