From def527584228071c5ed89db69899100fa35440f0 Mon Sep 17 00:00:00 2001 From: sebres Date: Wed, 17 Apr 2024 15:13:00 +0000 Subject: cherrypick [b73516f7cfccbc9f] to 8.7 - closes [167e0635db]: solves leaks, valgrind test, etc --- generic/tclClock.c | 52 ++++++++++++++++++++++++++++++++++++++++----------- generic/tclClockFmt.c | 14 +++++++------- generic/tclDate.h | 1 + 3 files changed, 49 insertions(+), 18 deletions(-) diff --git a/generic/tclClock.c b/generic/tclClock.c index 64bf57f..667cfbe 100644 --- a/generic/tclClock.c +++ b/generic/tclClock.c @@ -115,6 +115,7 @@ static struct tm * ThreadSafeLocalTime(const time_t *); static size_t TzsetIfNecessary(void); static void ClockDeleteCmdProc(void *); static Tcl_ObjCmdProc ClockSafeCatchCmd; +static void ClockFinalize(void *); /* * Structure containing description of "native" clock commands to create. */ @@ -180,6 +181,15 @@ TclClockInit( ClockClientData *data; int i; + static int initialized = 0; /* global clock engine initialized (in process) */ + /* + * Register handler to finalize clock on exit. + */ + if (!initialized) { + Tcl_CreateExitHandler(ClockFinalize, NULL); + initialized = 1; + } + /* * Safe interps get [::clock] as alias to a parent, so do not need their * own copies of the support routines. @@ -352,12 +362,14 @@ ClockDeleteCmdProc( for (i = 0; i < MCLIT__END; ++i) { Tcl_DecrRefCount(data->mcLiterals[i]); } + ckfree(data->mcLiterals); data->mcLiterals = NULL; } if (data->mcLitIdxs != NULL) { for (i = 0; i < MCLIT__END; ++i) { Tcl_DecrRefCount(data->mcLitIdxs[i]); } + ckfree(data->mcLitIdxs); data->mcLitIdxs = NULL; } @@ -4638,20 +4650,25 @@ ClockSafeCatchCmd( #endif #define TZ_INIT_MARKER ((WCHAR *) INT2PTR(-1)) +typedef struct ClockTzStatic { + WCHAR *was; /* Previous value of TZ. */ +#if TCL_MAJOR_VERSION > 8 + long long lastRefresh; /* Used for latency before next refresh. */ +#else + long lastRefresh; /* Used for latency before next refresh. */ +#endif + size_t epoch; /* Epoch, signals that TZ changed. */ + size_t envEpoch; /* Last env epoch, for faster signaling, + * that TZ changed via TCL */ +} ClockTzStatic; +static ClockTzStatic tz = { /* Global timezone info; protected by + * clockMutex.*/ + TZ_INIT_MARKER, 0, 0, 0 +}; + static size_t TzsetIfNecessary(void) { - typedef struct ClockTzStatic { - WCHAR *was; /* Previous value of TZ. */ - long lastRefresh; /* Used for latency before next refresh. */ - size_t epoch; /* Epoch, signals that TZ changed. */ - size_t envEpoch; /* Last env epoch, for faster signaling, - * that TZ changed via TCL */ - } ClockTzStatic; - static ClockTzStatic tz = { /* Global timezone info; protected by - * clockMutex.*/ - TZ_INIT_MARKER, 0, 0, 0 - }; const WCHAR *tzNow; /* Current value of TZ. */ Tcl_Time now; /* Current time. */ size_t epoch; /* The tz.epoch that the TZ was read at. */ @@ -4701,6 +4718,19 @@ TzsetIfNecessary(void) return epoch; } +static void +ClockFinalize( + TCL_UNUSED(void *)) +{ + ClockFrmScnFinalize(); + + if (tz.was && tz.was != TZ_INIT_MARKER) { + ckfree(tz.was); + } + + Tcl_MutexFinalize(&clockMutex); +} + /* * Local Variables: * mode: c diff --git a/generic/tclClockFmt.c b/generic/tclClockFmt.c index a616074..154c8ee 100644 --- a/generic/tclClockFmt.c +++ b/generic/tclClockFmt.c @@ -26,7 +26,6 @@ static void ClockFmtObj_UpdateString(Tcl_Obj *objPtr); TCL_DECLARE_MUTEX(ClockFmtMutex); /* Serializes access to common format list. */ static void ClockFmtScnStorageDelete(ClockFmtScnStorage *fss); -static void ClockFrmScnFinalize(void *); #ifndef TCL_CLOCK_FULL_COMPAT #define TCL_CLOCK_FULL_COMPAT 1 @@ -681,7 +680,7 @@ ClockFmtObj_FreeInternalRep( Tcl_Obj *objPtr) { ClockFmtScnStorage *fss = ObjClockFmtScn(objPtr); - if (fss != NULL) { + if (fss != NULL && initialized) { Tcl_MutexLock(&ClockFmtMutex); /* decrement object reference count of format/scan storage */ if (--fss->objRefCount <= 0) { @@ -835,7 +834,6 @@ FindOrCreateFmtScnStorage( &ClockFmtScnStorageHashKeyType); initialized = 1; - Tcl_CreateExitHandler(ClockFrmScnFinalize, NULL); } /* get or create entry (and alocate storage) */ @@ -3560,10 +3558,12 @@ ClockFrmScnClearCaches(void) Tcl_MutexUnlock(&ClockFmtMutex); } -static void -ClockFrmScnFinalize( - TCL_UNUSED(void *)) +void +ClockFrmScnFinalize() { + if (!initialized) { + return; + } Tcl_MutexLock(&ClockFmtMutex); #if CLOCK_FMT_SCN_STORAGE_GC_SIZE > 0 /* clear GC */ @@ -3572,8 +3572,8 @@ ClockFrmScnFinalize( ClockFmtScnStorage_GC.count = 0; #endif if (initialized) { - Tcl_DeleteHashTable(&FmtScnHashTable); initialized = 0; + Tcl_DeleteHashTable(&FmtScnHashTable); } Tcl_MutexUnlock(&ClockFmtMutex); Tcl_MutexFinalize(&ClockFmtMutex); diff --git a/generic/tclDate.h b/generic/tclDate.h index 1657528..fea7cbd 100644 --- a/generic/tclDate.h +++ b/generic/tclDate.h @@ -560,5 +560,6 @@ MODULE_SCOPE int ClockScan(DateInfo *info, Tcl_Obj *strObj, MODULE_SCOPE int ClockFormat(DateFormat *dateFmt, ClockFmtScnCmdArgs *opts); MODULE_SCOPE void ClockFrmScnClearCaches(void); +MODULE_SCOPE void ClockFrmScnFinalize(); #endif /* _TCLCLOCK_H */ -- cgit v0.12