Skip to content

Commit 3683b3a

Browse files
committed
Fix localtime/1 mem leak
espressif/esp-idf#9764 Signed-off-by: Peter M <petermm@gmail.com>
1 parent dbc1540 commit 3683b3a

1 file changed

Lines changed: 44 additions & 5 deletions

File tree

src/libAtomVM/nifs.c

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1728,6 +1728,40 @@ term nif_erlang_universaltime_0(Context *ctx, int argc, term argv[])
17281728
return build_datetime_from_tm(ctx, gmtime_r(&ts.tv_sec, &broken_down_time));
17291729
}
17301730

1731+
// Workaround for newlib setenv memory leak: use putenv with a fixed-size
1732+
// static buffer. The buffer is installed once and then modified in place.
1733+
// See: https://github.com/espressif/esp-idf/issues/3046
1734+
1735+
#define TZ_BUFFER_SIZE 64
1736+
1737+
static char tz_buffer[TZ_BUFFER_SIZE] = "TZ=";
1738+
static char tz_value_buffer[TZ_BUFFER_SIZE - 3];
1739+
static bool tz_buffer_installed = false;
1740+
static bool tz_buffer_in_place = false;
1741+
1742+
static void set_tz_value(const char *tz)
1743+
{
1744+
if (!tz_buffer_installed) {
1745+
putenv(tz_buffer);
1746+
tz_buffer_installed = true;
1747+
char *env_tz = getenv("TZ");
1748+
tz_buffer_in_place = (env_tz == tz_buffer + 3);
1749+
}
1750+
size_t tz_len = strlen(tz);
1751+
if (tz_len > TZ_BUFFER_SIZE - 4) {
1752+
tz_len = TZ_BUFFER_SIZE - 4;
1753+
}
1754+
if (tz_buffer_in_place) {
1755+
memcpy(tz_buffer + 3, tz, tz_len);
1756+
tz_buffer[3 + tz_len] = '\0';
1757+
} else {
1758+
memcpy(tz_value_buffer, tz, tz_len);
1759+
memset(tz_value_buffer + tz_len, ' ', (TZ_BUFFER_SIZE - 4) - tz_len);
1760+
tz_value_buffer[TZ_BUFFER_SIZE - 4] = '\0';
1761+
setenv("TZ", tz_value_buffer, 1);
1762+
}
1763+
}
1764+
17311765
term nif_erlang_localtime(Context *ctx, int argc, term argv[])
17321766
{
17331767
char *tz;
@@ -1751,17 +1785,22 @@ term nif_erlang_localtime(Context *ctx, int argc, term argv[])
17511785
smp_spinlock_lock(&ctx->global->env_spinlock);
17521786
#endif
17531787
if (tz) {
1754-
char *oldtz = getenv("TZ");
1755-
setenv("TZ", tz, 1);
1788+
char *oldtz = NULL;
1789+
char *oldtz_env = getenv("TZ");
1790+
if (oldtz_env) {
1791+
oldtz = strdup(oldtz_env);
1792+
}
1793+
set_tz_value(tz);
17561794
tzset();
17571795
localtime = localtime_r(&ts.tv_sec, &storage);
17581796
if (oldtz) {
1759-
setenv("TZ", oldtz, 1);
1797+
set_tz_value(oldtz);
1798+
free(oldtz);
17601799
} else {
1761-
unsetenv("TZ");
1800+
set_tz_value("");
17621801
}
1802+
tzset();
17631803
} else {
1764-
// Call tzset to handle DST changes
17651804
tzset();
17661805
localtime = localtime_r(&ts.tv_sec, &storage);
17671806
}

0 commit comments

Comments
 (0)