Skip to content

Commit

Permalink
Use 64 bits for time_t (emscripten-core#17401)
Browse files Browse the repository at this point in the history
This brings us back in line with upstream musl.  The change to 32-bit
was only recently made in emscripten-core#16966. The reason we made this change was
made was because we had certain C library calls that were implemented in
JS that returned `time_t`.  Since returning 64-bit values from JS
functions is not always easy (we don't always have WASM_BIGINT
available) that simplest solution was to define `time_t` to 32-bit which
doesn't have issues at the JS boundary.

However, in the intervening time many of the `time_t`-returning function
have been moved into native code (See emscripten-core#16606 and emscripten-core#16439) with only two
remaining: _mktime_js and _timegm_js.  So this change redefines just
those two functions to return `int` while keeping `time_t` itself as
64-bit.

Fixes: emscripten-core#17393
  • Loading branch information
sbc100 authored and arbiny committed Jul 22, 2022
1 parent 86ab79c commit bc0fefd
Show file tree
Hide file tree
Showing 7 changed files with 30 additions and 29 deletions.
2 changes: 2 additions & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ See docs/process.md for more on how version tagging works.
- The getWasmTableEntry/setWasmTableEntry library function are no longer
included by default. Add them to `DEFAULT_LIBRARY_FUNCS_TO_INCLUDE` or
`EXPORTED_RUNTIME_METHODS` if you want to use them outside of JS library code.
- The type of `time_t` was restored 64-bit after being converted to 32-bit in
3.1.11. (#17401)

3.1.15 - 07/01/2022
-------------------
Expand Down
8 changes: 6 additions & 2 deletions system/lib/libc/emscripten_time.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ __attribute__((__weak__)) int daylight = 0;
__attribute__((__weak__)) char *tzname[2] = { 0, 0 };

void _tzset_js(long* timezone, int* daylight, char** tzname);
time_t _timegm_js(struct tm *tm);
time_t _mktime_js(struct tm *tm);
// Declare these functions `int` rather than time_t to avoid int64 at the wasm
// boundary (avoids 64-bit complexity at the boundary when WASM_BIGINT is
// missing).
// TODO(sbc): Covert back to `time_t` before 2038 ...
int _timegm_js(struct tm *tm);
int _mktime_js(struct tm *tm);
void _localtime_js(const time_t *restrict t, struct tm *restrict tm);
void _gmtime_js(const time_t *restrict t, struct tm *restrict tm);
double _emscripten_date_now();
Expand Down
2 changes: 1 addition & 1 deletion system/lib/libc/musl/arch/emscripten/bits/alltypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ typedef long double double_t;
#endif

#if defined(__NEED_time_t) && !defined(__DEFINED_time_t)
typedef int time_t; /* XXX EMSCRIPTEN: ensure it's always 32-bits even in wasm64 */
typedef _Int64 time_t;
#define __DEFINED_time_t
#endif

Expand Down
8 changes: 4 additions & 4 deletions system/lib/libc/musl/include/inttypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,14 +22,14 @@ uintmax_t strtoumax(const char *__restrict, char **__restrict, int);
intmax_t wcstoimax(const wchar_t *__restrict, wchar_t **__restrict, int);
uintmax_t wcstoumax(const wchar_t *__restrict, wchar_t **__restrict, int);

#if UINTPTR_MAX == UINT64_MAX
#define __PRI64 "l"
#define __PRIPTR "l"
#elif defined(__EMSCRIPTEN__)
#if defined(__EMSCRIPTEN__)
// Under emscripten __PTRDIFF_TYPE__ and therefor intptr_t are defined to
// be `long int` even on wasm32.
#define __PRI64 "ll"
#define __PRIPTR "l"
#elif UINTPTR_MAX == UINT64_MAX
#define __PRI64 "l"
#define __PRIPTR "l"
#else
#define __PRI64 "ll"
#define __PRIPTR ""
Expand Down
8 changes: 1 addition & 7 deletions system/lib/libc/musl/src/time/clock.c
Original file line number Diff line number Diff line change
@@ -1,20 +1,14 @@
#include <time.h>
#include <limits.h>

#ifdef __EMSCRIPTEN__
#define TIME_T_MAX INT_MAX
#else
#define TIME_T_MAX LONG_MAX
#endif

clock_t clock()
{
struct timespec ts;

if (__clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts))
return -1;

if (ts.tv_sec > TIME_T_MAX/1000000
if (ts.tv_sec > LONG_MAX/1000000
|| ts.tv_nsec/1000 > LONG_MAX-1000000*ts.tv_sec)
return -1;

Expand Down
24 changes: 12 additions & 12 deletions tests/reference_struct_info.json
Original file line number Diff line number Diff line change
Expand Up @@ -1410,30 +1410,30 @@
"sin6_scope_id": 24
},
"stat": {
"__size__": 88,
"__size__": 112,
"__st_dev_padding": 4,
"__st_ino_truncated": 8,
"__st_rdev_padding": 32,
"st_atim": {
"__size__": 8,
"tv_nsec": 60,
"__size__": 16,
"tv_nsec": 64,
"tv_sec": 56
},
"st_blksize": 48,
"st_blocks": 52,
"st_ctim": {
"__size__": 8,
"tv_nsec": 76,
"tv_sec": 72
"__size__": 16,
"tv_nsec": 96,
"tv_sec": 88
},
"st_dev": 0,
"st_gid": 24,
"st_ino": 80,
"st_ino": 104,
"st_mode": 12,
"st_mtim": {
"__size__": 8,
"tv_nsec": 68,
"tv_sec": 64
"__size__": 16,
"tv_nsec": 80,
"tv_sec": 72
},
"st_nlink": 16,
"st_rdev": 28,
Expand Down Expand Up @@ -1461,8 +1461,8 @@
"timeSpentInStatus": 16
},
"timespec": {
"__size__": 8,
"tv_nsec": 4,
"__size__": 16,
"tv_nsec": 8,
"tv_sec": 0
},
"tm": {
Expand Down
7 changes: 4 additions & 3 deletions tests/utime/test_utime.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include <assert.h>
#include <errno.h>
#include <inttypes.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
Expand Down Expand Up @@ -51,9 +52,9 @@ void test() {
stat("writeable", &s);
assert(s.st_atime == s.st_mtime);
time_t diff = s.st_atime - now;
if (abs(diff) > 5) {
fprintf(stderr, "st_atime: %i, now: %i, diff: %i\n ", s.st_atime, now, diff);
assert(abs(diff) <= 5);
if (llabs(diff) > 5) {
fprintf(stderr, "st_atime: %" PRId64 ", now: %" PRId64 ", diff: %" PRId64 "\n ", s.st_atime, now, diff);
assert(llabs(diff) <= 5);
}

// write permissions aren't checked when setting node
Expand Down

0 comments on commit bc0fefd

Please sign in to comment.