This is an automated email from the git hooks/post-receive script.
git pushed a commit to branch tymux
in repository terminology.
View the commit online.
commit d23f3599d6eca48365aa89bf4de198f5542bd7be
Author: [email protected] <[email protected]>
AuthorDate: Mon Mar 16 15:45:57 2026 -0600
fix: initialize and cleanup shadow Termpty correctly in tymux mode
The shadow pty was under-initialized, causing valgrind errors and
potential crashes when cells with hyperlinks were rendered. Initialize
the hyperlink bitmap and links array (65536 slots) to match termpty_new,
add proper config pointer and wrap mode, and implement complete cleanup
in _shadow_pty_free to free all allocated resources.
- _shadow_pty_new: accept Config pointer; allocate hl.bitmap and
hl.links (full HL_LINKS_MAX entries pre-allocated to prevent NULL
deref); set termstate.wrap=1; remove dead write_cb assignment
- _shadow_pty_free: cleanup prop.title, prop.icon, prop.user_title,
hl.links (with term_link_free loop), hl.bitmap, tabs, back, buf,
write_buffer to match termpty_free
- termsession_attach: pass Config to shadow pty
- termio: guard termpty_config_update for session-mode ptys; pass
config to termsession_attach
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
---
src/bin/termio.c | 11 ++++++++--
src/bin/termsession.c | 60 +++++++++++++++++++++++++++++++++++++++++++++++----
src/bin/termsession.h | 2 ++
3 files changed, 67 insertions(+), 6 deletions(-)
diff --git a/src/bin/termio.c b/src/bin/termio.c
index 69102ef5..ab3292ca 100644
--- a/src/bin/termio.c
+++ b/src/bin/termio.c
@@ -541,7 +541,14 @@ termio_config_update(Evas_Object *obj)
sd->jump_on_change = sd->config->jump_on_change;
sd->jump_on_keypress = sd->config->jump_on_keypress;
- termpty_config_update(sd->pty, sd->config);
+#ifdef HAVE_TYMUX
+ /* Shadow pty has no real PTY and no scrollback; only update the config
+ * pointer so rendering picks up colour/font state changes. */
+ if (sd->session)
+ sd->pty->config = sd->config;
+ else
+#endif
+ termpty_config_update(sd->pty, sd->config);
sd->scroll = 0;
colors_term_init(sd->grid.obj, sd->config->color_scheme);
@@ -4322,7 +4329,7 @@ termio_add(Evas_Object *win, Config *config,
{
sd->session_name = eina_stringshare_add(session_name);
Termpty *spty = NULL;
- sd->session = termsession_attach(session_name, w, h, &spty);
+ sd->session = termsession_attach(session_name, w, h, config, &spty);
if (!sd->session)
{
ERR("Could not attach to tymux session '%s'", session_name);
diff --git a/src/bin/termsession.c b/src/bin/termsession.c
index 9235c645..72d8fa05 100644
--- a/src/bin/termsession.c
+++ b/src/bin/termsession.c
@@ -38,7 +38,7 @@ _session_write_cb(const char *buf, int len, void *data)
/* ── shadow Termpty ─────────────────────────────────────────────────── */
static Termpty *
-_shadow_pty_new(TermSession *ts, int cols, int rows)
+_shadow_pty_new(TermSession *ts, int cols, int rows, Config *config)
{
Termpty *ty;
@@ -51,6 +51,10 @@ _shadow_pty_new(TermSession *ts, int cols, int rows)
ty->pid = -1;
ty->w = cols;
ty->h = rows;
+ ty->config = config;
+
+ /* wrap=1 is the correct out-of-the-box terminal default */
+ ty->termstate.wrap = 1;
ty->screen = calloc((size_t)(cols * rows), sizeof(Termcell));
if (!ty->screen)
@@ -67,8 +71,35 @@ _shadow_pty_new(TermSession *ts, int cols, int rows)
return NULL;
}
- ty->write_cb.func = _session_write_cb;
- ty->write_cb.data = ""
+ /* hl.bitmap: allocate to prevent NULL-deref if any hyperlink escape
+ * or rendering path checks it. Mark slot 0 used, same as termpty_new. */
+ ty->hl.bitmap = calloc(1, HL_LINKS_MAX / 8);
+ if (!ty->hl.bitmap)
+ {
+ free(ty->screen2);
+ free(ty->screen);
+ free(ty);
+ return NULL;
+ }
+ ty->hl.bitmap[0] = 1;
+
+ /* hl.links: allocate the full HL_LINKS_MAX entries (zero-initialised) so
+ * that any link_id received from the daemon can be safely dereferenced by
+ * termio and termpty.h inline helpers without bounds checks. hl.size is
+ * set to match, mirroring the bitmap coverage. */
+ ty->hl.links = calloc(HL_LINKS_MAX, sizeof(Term_Link));
+ if (!ty->hl.links)
+ {
+ free(ty->hl.bitmap);
+ free(ty->screen2);
+ free(ty->screen);
+ free(ty);
+ return NULL;
+ }
+ ty->hl.size = HL_LINKS_MAX;
+
+ /* write_cb is intentionally left unset here; the caller (termsession_attach)
+ * wires it once the TermSession is fully constructed. */
return ty;
}
@@ -78,8 +109,28 @@ _shadow_pty_free(Termpty *ty)
{
if (!ty)
return;
+ eina_stringshare_del(ty->prop.title);
+ eina_stringshare_del(ty->prop.user_title);
+ eina_stringshare_del(ty->prop.icon);
free(ty->screen);
free(ty->screen2);
+ if (ty->hl.links)
+ {
+ uint16_t i;
+
+ for (i = 0; i < ty->hl.size; i++)
+ {
+ Term_Link *l = ty->hl.links + i;
+
+ term_link_free(ty, l);
+ }
+ free(ty->hl.links);
+ }
+ free(ty->hl.bitmap);
+ free(ty->buf);
+ ty_sb_free(&ty->write_buffer);
+ free(ty->tabs);
+ free(ty->back);
free(ty);
}
@@ -277,6 +328,7 @@ _ensure_daemon(const char *session_name, const char *sock_path)
TermSession *
termsession_attach(const char *session_name,
int cols, int rows,
+ Config *config,
Termpty **shadow_pty_out)
{
char sock_path[256];
@@ -370,7 +422,7 @@ termsession_attach(const char *session_name,
/* Use requested cols/rows for the shadow pty; _sync_shadow will
* adjust to whatever the server reports in the header. */
- ty = _shadow_pty_new(NULL, cols, rows);
+ ty = _shadow_pty_new(NULL, cols, rows, config);
if (!ty)
{
ERR("termsession: failed to allocate shadow pty");
diff --git a/src/bin/termsession.h b/src/bin/termsession.h
index 1df9148e..a6af826d 100644
--- a/src/bin/termsession.h
+++ b/src/bin/termsession.h
@@ -8,6 +8,7 @@
#include <Eina.h>
#include <Ecore.h>
#include <Ecore_Evas_Types.h>
+#include "config.h"
#include "termpty.h"
#include "termsrv.h"
@@ -39,6 +40,7 @@ struct _TermSession {
*/
TermSession *termsession_attach(const char *session_name,
int cols, int rows,
+ Config *config,
Termpty **shadow_pty_out);
/* Send DETACH, munmap, close socket, free shadow Termpty. */
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.