From 303edb71bda9515605e41bdb323203bc24d15c90 Mon Sep 17 00:00:00 2001 From: nicm Date: Wed, 22 Apr 2026 07:05:03 +0000 Subject: [PATCH] Add a fairly low time limit to format evaluation to stop absurdly nested formats from making tmux appear to hang. --- format.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/format.c b/format.c index 88fb227a..90537879 100644 --- a/format.c +++ b/format.c @@ -120,6 +120,9 @@ format_job_cmp(struct format_job *fj1, struct format_job *fj2) /* Limit on recursion. */ #define FORMAT_LOOP_LIMIT 100 +/* Limit on time taken (milliseconds). */ +#define FORMAT_TIME_LIMIT 100 + /* Format expand flags. */ #define FORMAT_EXPAND_TIME 0x1 #define FORMAT_EXPAND_NOJOBS 0x2 @@ -169,9 +172,11 @@ RB_GENERATE_STATIC(format_entry_tree, format_entry, entry, format_entry_cmp); struct format_expand_state { struct format_tree *ft; u_int loop; + uint64_t start_time; + int flags; + time_t time; struct tm tm; - int flags; }; /* Format modifier. */ @@ -292,6 +297,7 @@ format_copy_state(struct format_expand_state *to, to->time = from->time; memcpy(&to->tm, &from->tm, sizeof to->tm); to->flags = from->flags|flags; + to->start_time = from->start_time; } /* Format job update callback. */ @@ -5514,10 +5520,16 @@ format_expand1(struct format_expand_state *es, const char *fmt) size_t off, len, n, outlen; int ch, brackets; char expanded[8192]; + uint64_t t = get_timer(); if (fmt == NULL || *fmt == '\0') return (xstrdup("")); + if (t - es->start_time >= FORMAT_TIME_LIMIT) { + format_log(es, "reached time limit (%llu)", + (unsigned long long)(t - es->start_time)); + return (xstrdup("")); + } if (es->loop == FORMAT_LOOP_LIMIT) { format_log(es, "reached loop limit (%u)", FORMAT_LOOP_LIMIT); return (xstrdup("")); @@ -5683,6 +5695,7 @@ format_expand_time(struct format_tree *ft, const char *fmt) memset(&es, 0, sizeof es); es.ft = ft; es.flags = FORMAT_EXPAND_TIME; + es.start_time = get_timer(); return (format_expand1(&es, fmt)); } @@ -5695,6 +5708,7 @@ format_expand(struct format_tree *ft, const char *fmt) memset(&es, 0, sizeof es); es.ft = ft; es.flags = 0; + es.start_time = get_timer(); return (format_expand1(&es, fmt)); }