Skip to content

Commit 4003202

Browse files
authored
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.
1 parent dc849e9 commit 4003202

File tree

1 file changed

+18
-25
lines changed

1 file changed

+18
-25
lines changed

src/builtin.c

Lines changed: 18 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,6 @@
1111
#include <sys/time.h>
1212
#include <stdlib.h>
1313
#include <stddef.h>
14-
#ifdef HAVE_ALLOCA_H
15-
# include <alloca.h>
16-
#elif !defined alloca
17-
# ifdef __GNUC__
18-
# define alloca __builtin_alloca
19-
# elif defined _MSC_VER
20-
# include <malloc.h>
21-
# define alloca _alloca
22-
# elif !defined HAVE_ALLOCA
23-
# ifdef __cplusplus
24-
extern "C"
25-
# endif
26-
void *alloca (size_t);
27-
# endif
28-
#endif
2914
#include <assert.h>
3015
#include <ctype.h>
3116
#include <limits.h>
@@ -1768,16 +1753,16 @@ static jv f_strftime(jq_state *jq, jv a, jv b) {
17681753
return ret_error(b, jv_string("strftime/1 requires parsed datetime inputs"));
17691754

17701755
const char *fmt = jv_string_value(b);
1771-
size_t alloced = strlen(fmt) + 100;
1772-
char *buf = alloca(alloced);
1756+
size_t max_size = strlen(fmt) + 100;
1757+
char *buf = jv_mem_alloc(max_size);
17731758
#ifdef __APPLE__
17741759
/* Apple Libc (as of version 1669.40.2) contains a bug which causes it to
17751760
* ignore the `tm.tm_gmtoff` in favor of the global timezone. To print the
17761761
* proper timezone offset we temporarily switch the TZ to UTC. */
17771762
char *tz = (tz = getenv("TZ")) != NULL ? strdup(tz) : NULL;
17781763
setenv("TZ", "UTC", 1);
17791764
#endif
1780-
size_t n = strftime(buf, alloced, fmt, &tm);
1765+
size_t n = strftime(buf, max_size, fmt, &tm);
17811766
#ifdef __APPLE__
17821767
if (tz) {
17831768
setenv("TZ", tz, 1);
@@ -1788,9 +1773,13 @@ static jv f_strftime(jq_state *jq, jv a, jv b) {
17881773
#endif
17891774
jv_free(b);
17901775
/* POSIX doesn't provide errno values for strftime() failures; weird */
1791-
if (n == 0 || n > alloced)
1776+
if ((n == 0 && *fmt) || n > max_size) {
1777+
free(buf);
17921778
return jv_invalid_with_msg(jv_string("strftime/1: unknown system failure"));
1793-
return jv_string(buf);
1779+
}
1780+
jv ret = jv_string_sized(buf, n);
1781+
free(buf);
1782+
return ret;
17941783
}
17951784
#else
17961785
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) {
18131802
if (!jv2tm(a, &tm, 1))
18141803
return ret_error(b, jv_string("strflocaltime/1 requires parsed datetime inputs"));
18151804
const char *fmt = jv_string_value(b);
1816-
size_t alloced = strlen(fmt) + 100;
1817-
char *buf = alloca(alloced);
1818-
size_t n = strftime(buf, alloced, fmt, &tm);
1805+
size_t max_size = strlen(fmt) + 100;
1806+
char *buf = jv_mem_alloc(max_size);
1807+
size_t n = strftime(buf, max_size, fmt, &tm);
18191808
jv_free(b);
18201809
/* POSIX doesn't provide errno values for strftime() failures; weird */
1821-
if (n == 0 || n > alloced)
1810+
if ((n == 0 && *fmt) || n > max_size) {
1811+
free(buf);
18221812
return jv_invalid_with_msg(jv_string("strflocaltime/1: unknown system failure"));
1823-
return jv_string(buf);
1813+
}
1814+
jv ret = jv_string_sized(buf, n);
1815+
free(buf);
1816+
return ret;
18241817
}
18251818
#else
18261819
static jv f_strflocaltime(jq_state *jq, jv a, jv b) {

0 commit comments

Comments
 (0)