builtin.c: jv2tm: fix UB and accept array inputs with not all the values
Now, time functions accept array inputs even if they don't have all the elements, 0 will be assumed if a value is not present. Also, jv2tm now properly clamps large number values to a signed 32-bit integer and rejects nan. Fixes https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=65885
This commit is contained in:
1 parent
d69733154a
commit
bc96146825
2 files changed
+31
-21
No files matched your search
+27
-21
@@ -1461,30 +1461,35 @@ static jv f_strptime(jq_state *jq, jv a, jv b) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define TO_TM_FIELD(t, j, i) \
|
|
||||||
do { \
|
|
||||||
jv n = jv_array_get(jv_copy(j), (i)); \
|
|
||||||
if (jv_get_kind(n) != (JV_KIND_NUMBER)) { \
|
|
||||||
jv_free(n); \
|
|
||||||
jv_free(j); \
|
|
||||||
return 0; \
|
|
||||||
} \
|
|
||||||
t = jv_number_value(n); \
|
|
||||||
jv_free(n); \
|
|
||||||
} while (0)
|
|
||||||
|
|
||||||
static int jv2tm(jv a, struct tm *tm) {
|
static int jv2tm(jv a, struct tm *tm) {
|
||||||
memset(tm, 0, sizeof(*tm));
|
memset(tm, 0, sizeof(*tm));
|
||||||
TO_TM_FIELD(tm->tm_year, a, 0);
|
static size_t offsets[] = {
|
||||||
tm->tm_year -= 1900;
|
offsetof(struct tm, tm_year),
|
||||||
TO_TM_FIELD(tm->tm_mon, a, 1);
|
offsetof(struct tm, tm_mon),
|
||||||
TO_TM_FIELD(tm->tm_mday, a, 2);
|
offsetof(struct tm, tm_mday),
|
||||||
TO_TM_FIELD(tm->tm_hour, a, 3);
|
offsetof(struct tm, tm_hour),
|
||||||
TO_TM_FIELD(tm->tm_min, a, 4);
|
offsetof(struct tm, tm_min),
|
||||||
TO_TM_FIELD(tm->tm_sec, a, 5);
|
offsetof(struct tm, tm_sec),
|
||||||
TO_TM_FIELD(tm->tm_wday, a, 6);
|
offsetof(struct tm, tm_wday),
|
||||||
TO_TM_FIELD(tm->tm_yday, a, 7);
|
offsetof(struct tm, tm_yday),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (size_t i = 0; i < (sizeof offsets / sizeof *offsets); ++i) {
|
||||||
|
jv n = jv_array_get(jv_copy(a), i);
|
||||||
|
if (!jv_is_valid(n))
|
||||||
|
break;
|
||||||
|
if (jv_get_kind(n) != JV_KIND_NUMBER || jvp_number_is_nan(n)) {
|
||||||
jv_free(a);
|
jv_free(a);
|
||||||
|
jv_free(n);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
double d = jv_number_value(n);
|
||||||
|
if (i == 0) /* year */
|
||||||
|
d -= 1900;
|
||||||
|
*(int *)((void *)tm + offsets[i]) = d < INT_MIN ? INT_MIN :
|
||||||
|
d > INT_MAX ? INT_MAX : (int)d;
|
||||||
|
jv_free(n);
|
||||||
|
}
|
||||||
|
|
||||||
// We use UTC everywhere (gettimeofday, gmtime) and UTC does not do DST.
|
// We use UTC everywhere (gettimeofday, gmtime) and UTC does not do DST.
|
||||||
// Setting tm_isdst to 0 is done by the memset.
|
// Setting tm_isdst to 0 is done by the memset.
|
||||||
@@ -1494,6 +1499,7 @@ static int jv2tm(jv a, struct tm *tm) {
|
|||||||
// hope it is okay to initialize them to zero, because the standard does not
|
// hope it is okay to initialize them to zero, because the standard does not
|
||||||
// provide an alternative.
|
// provide an alternative.
|
||||||
|
|
||||||
|
jv_free(a);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1568,6 +1568,10 @@ strftime("%A, %B %d, %Y")
|
|||||||
1435677542.822351
|
1435677542.822351
|
||||||
"Tuesday, June 30, 2015"
|
"Tuesday, June 30, 2015"
|
||||||
|
|
||||||
|
strftime("%Y-%m-%dT%H:%M:%SZ")
|
||||||
|
[2024,2,15]
|
||||||
|
"2024-03-15T00:00:00Z"
|
||||||
|
|
||||||
gmtime
|
gmtime
|
||||||
1425599507
|
1425599507
|
||||||
[2015,2,5,23,51,47,4,63]
|
[2015,2,5,23,51,47,4,63]
|
||||||
|
|||||||
Reference in new issue
Block a user