Fix segmentation fault on strftime/1 and strflocaltime/1 (#3271)
When we use a large format string to `strftime/1` and `strflocaltime/1`, we get segmentation fault. This happens because the result buffer is allocated on the stack using `alloca` function, and `strftime` function writes out of the space when the size is not enough to format time. I fixed the segmentation fault issue by allocating the result buffer on the heap using `malloc` function, because `alloca` function does not provide a way to detect insufficient space.
This commit is contained in:
1 parent
dc849e9bb7
commit
4003202ccf
1 file changed
+18
-25
+18
-25
@@ -11,21 +11,6 @@
|
||||
#include <sys/time.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#ifdef HAVE_ALLOCA_H
|
||||
# include <alloca.h>
|
||||
#elif !defined alloca
|
||||
# ifdef __GNUC__
|
||||
# define alloca __builtin_alloca
|
||||
# elif defined _MSC_VER
|
||||
# include <malloc.h>
|
||||
# define alloca _alloca
|
||||
# elif !defined HAVE_ALLOCA
|
||||
# ifdef __cplusplus
|
||||
extern "C"
|
||||
# endif
|
||||
void *alloca (size_t);
|
||||
# endif
|
||||
#endif
|
||||
#include <assert.h>
|
||||
#include <ctype.h>
|
||||
#include <limits.h>
|
||||
@@ -1768,8 +1753,8 @@ static jv f_strftime(jq_state *jq, jv a, jv b) {
|
||||
return ret_error(b, jv_string("strftime/1 requires parsed datetime inputs"));
|
||||
|
||||
const char *fmt = jv_string_value(b);
|
||||
size_t alloced = strlen(fmt) + 100;
|
||||
char *buf = alloca(alloced);
|
||||
size_t max_size = strlen(fmt) + 100;
|
||||
char *buf = jv_mem_alloc(max_size);
|
||||
#ifdef __APPLE__
|
||||
/* Apple Libc (as of version 1669.40.2) contains a bug which causes it to
|
||||
* ignore the `tm.tm_gmtoff` in favor of the global timezone. To print the
|
||||
@@ -1777,7 +1762,7 @@ static jv f_strftime(jq_state *jq, jv a, jv b) {
|
||||
char *tz = (tz = getenv("TZ")) != NULL ? strdup(tz) : NULL;
|
||||
setenv("TZ", "UTC", 1);
|
||||
#endif
|
||||
size_t n = strftime(buf, alloced, fmt, &tm);
|
||||
size_t n = strftime(buf, max_size, fmt, &tm);
|
||||
#ifdef __APPLE__
|
||||
if (tz) {
|
||||
setenv("TZ", tz, 1);
|
||||
@@ -1788,9 +1773,13 @@ static jv f_strftime(jq_state *jq, jv a, jv b) {
|
||||
#endif
|
||||
jv_free(b);
|
||||
/* POSIX doesn't provide errno values for strftime() failures; weird */
|
||||
if (n == 0 || n > alloced)
|
||||
if ((n == 0 && *fmt) || n > max_size) {
|
||||
free(buf);
|
||||
return jv_invalid_with_msg(jv_string("strftime/1: unknown system failure"));
|
||||
return jv_string(buf);
|
||||
}
|
||||
jv ret = jv_string_sized(buf, n);
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static jv f_strftime(jq_state *jq, jv a, jv b) {
|
||||
@@ -1813,14 +1802,18 @@ static jv f_strflocaltime(jq_state *jq, jv a, jv b) {
|
||||
if (!jv2tm(a, &tm, 1))
|
||||
return ret_error(b, jv_string("strflocaltime/1 requires parsed datetime inputs"));
|
||||
const char *fmt = jv_string_value(b);
|
||||
size_t alloced = strlen(fmt) + 100;
|
||||
char *buf = alloca(alloced);
|
||||
size_t n = strftime(buf, alloced, fmt, &tm);
|
||||
size_t max_size = strlen(fmt) + 100;
|
||||
char *buf = jv_mem_alloc(max_size);
|
||||
size_t n = strftime(buf, max_size, fmt, &tm);
|
||||
jv_free(b);
|
||||
/* POSIX doesn't provide errno values for strftime() failures; weird */
|
||||
if (n == 0 || n > alloced)
|
||||
if ((n == 0 && *fmt) || n > max_size) {
|
||||
free(buf);
|
||||
return jv_invalid_with_msg(jv_string("strflocaltime/1: unknown system failure"));
|
||||
return jv_string(buf);
|
||||
}
|
||||
jv ret = jv_string_sized(buf, n);
|
||||
free(buf);
|
||||
return ret;
|
||||
}
|
||||
#else
|
||||
static jv f_strflocaltime(jq_state *jq, jv a, jv b) {
|
||||
|
||||
Reference in new issue
Block a user