summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMikael Magnusson <mikachu@gmail.com>2026-05-12 22:57:47 +0200
committerMikael Magnusson <mikachu@gmail.com>2026-05-16 18:28:31 +0200
commit458ce89509f8ddeadad3c2b3d5f19f73bfc37610 (patch)
treea5969724a5ca2526b4cc8b75d34fc6f0f37c39d1
parent54563: stat, system: minor fixes (diff)
downloadzsh-458ce89509f8ddeadad3c2b3d5f19f73bfc37610.tar
zsh-458ce89509f8ddeadad3c2b3d5f19f73bfc37610.tar.gz
zsh-458ce89509f8ddeadad3c2b3d5f19f73bfc37610.tar.bz2
zsh-458ce89509f8ddeadad3c2b3d5f19f73bfc37610.tar.lz
zsh-458ce89509f8ddeadad3c2b3d5f19f73bfc37610.tar.xz
zsh-458ce89509f8ddeadad3c2b3d5f19f73bfc37610.tar.zst
zsh-458ce89509f8ddeadad3c2b3d5f19f73bfc37610.zip
54564: termcap, terminfo: reset u, fix metafy confusion
Ideally, these should just be unmetafy()d and passed to ncurses, but the reality is that ncurses will just segfault if we do that when the user passes a non-ascii value. % echo $terminfo[らしりれ] zsh: segmentation fault % echotc れりの zsh: segmentation fault The tparm values do seem to work fine with multibyte strings, so do unmetafy() for those.
-rw-r--r--ChangeLog3
-rw-r--r--Src/Modules/termcap.c39
-rw-r--r--Src/Modules/terminfo.c33
3 files changed, 52 insertions, 23 deletions
diff --git a/ChangeLog b/ChangeLog
index e7768cc1d..19d7b4451 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,8 @@
2026-05-16 Mikael Magnusson <mikachu@gmail.com>
+ * 54564: Src/Modules/termcap.c, Src/Modules/terminfo.c: termcap,
+ terminfo: reset u, fix metafy confusion
+
* 54563: Src/Modules/stat.c, Src/Modules/system.c: stat, system:
minor fixes
diff --git a/Src/Modules/termcap.c b/Src/Modules/termcap.c
index af4009a3a..fade8f151 100644
--- a/Src/Modules/termcap.c
+++ b/Src/Modules/termcap.c
@@ -51,7 +51,7 @@ static char *boolcodes[] = {
/**/
static int
-ztgetflag(char *s)
+ztgetflag(const char *s)
{
char **b;
@@ -82,11 +82,20 @@ bin_echotc(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
char *s, buf[2048], *t, *u;
int num, argct;
- s = *argv++;
if (termflags & TERM_BAD)
return 1;
if ((termflags & TERM_UNKNOWN) && (isset(INTERACTIVE) || !init_term()))
return 1;
+
+ s = *argv++;
+ for (t = s; *t; t++) {
+ /* ncurses helpfully just crashes if you pass it nonascii */
+ if ((unsigned char)*t > 0x7f) {
+ zwarnnam(name, "no such capability: %s", s);
+ return 1;
+ }
+ }
+
/* if the specified termcap has a numeric value, display it */
if ((num = tgetnum(s)) != -1) {
printf("%d\n", num);
@@ -143,8 +152,9 @@ static struct builtin bintab[] = {
static HashNode
gettermcap(UNUSED(HashTable ht), const char *name)
{
- int len, num;
- char *tcstr, buf[2048], *u, *nameu;
+ int num;
+ char *tcstr, buf[2048], *u;
+ const char *t;
Param pm = NULL;
/* This depends on the termcap stuff in init.c */
@@ -153,18 +163,21 @@ gettermcap(UNUSED(HashTable ht), const char *name)
if ((termflags & TERM_UNKNOWN) && (isset(INTERACTIVE) || !init_term()))
return NULL;
-
- nameu = dupstring(name);
- unmetafy(nameu, &len);
+ for (t = name; *t; t++) {
+ /* ncurses helpfully just crashes if you pass it nonascii */
+ if ((unsigned char)*t > 0x7f) {
+ return NULL;
+ }
+ }
pm = (Param) hcalloc(sizeof(struct param));
- pm->node.nam = nameu;
+ pm->node.nam = dupstring(name);
pm->node.flags = PM_READONLY;
u = buf;
/* logic in the following cascade copied from echotc, above */
- if ((num = tgetnum(nameu)) != -1) {
+ if ((num = tgetnum(name)) != -1) {
pm->gsu.i = &nullsetinteger_gsu;
pm->u.val = num;
pm->node.flags |= PM_INTEGER;
@@ -172,7 +185,7 @@ gettermcap(UNUSED(HashTable ht), const char *name)
}
pm->gsu.s = &nullsetscalar_gsu;
- switch (ztgetflag(nameu)) {
+ switch (ztgetflag(name)) {
case -1:
break;
case 0:
@@ -184,7 +197,7 @@ gettermcap(UNUSED(HashTable ht), const char *name)
pm->node.flags |= PM_SCALAR;
return &pm->node;
}
- if ((tcstr = tgetstr(nameu, &u)) != NULL && tcstr != (char *)-1) {
+ if ((tcstr = tgetstr(name, &u)) != NULL && tcstr != (char *)-1) {
pm->u.str = dupstring(tcstr);
pm->node.flags |= PM_SCALAR;
} else {
@@ -201,7 +214,7 @@ scantermcap(UNUSED(HashTable ht), ScanFunc func, int flags)
{
Param pm = NULL;
int num;
- char **capcode, *tcstr, buf[2048], *u;
+ char **capcode, *tcstr, buf[2048];
#ifndef HAVE_NUMCODES
static char *numcodes[] = {
@@ -252,7 +265,6 @@ scantermcap(UNUSED(HashTable ht), ScanFunc func, int flags)
#endif
pm = (Param) hcalloc(sizeof(struct param));
- u = buf;
pm->node.flags = PM_READONLY | PM_SCALAR;
pm->gsu.s = &nullsetscalar_gsu;
@@ -286,6 +298,7 @@ scantermcap(UNUSED(HashTable ht), ScanFunc func, int flags)
zstrcodes
#endif
; *capcode; capcode++) {
+ char *u = buf;
if ((tcstr = (char *)tgetstr(*capcode,&u)) != NULL &&
tcstr != (char *)-1) {
pm->u.str = dupstring(tcstr);
diff --git a/Src/Modules/terminfo.c b/Src/Modules/terminfo.c
index f9ab64fb3..7ce162e81 100644
--- a/Src/Modules/terminfo.c
+++ b/Src/Modules/terminfo.c
@@ -68,12 +68,20 @@ bin_echoti(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
long pars[] = {0, 0, 0, 0, 0, 0, 0, 0, 0};
char *strcap[] = { "pfkey", "pfloc", "pfx", "pln", "pfxl", NULL };
- s = *argv++;
/* This depends on the termcap stuff in init.c */
if (termflags & TERM_BAD)
return 1;
if ((termflags & TERM_UNKNOWN) && (isset(INTERACTIVE) || !init_term()))
return 1;
+
+ s = *argv++;
+ for (t = s; *t; t++) {
+ /* ncurses helpfully just crashes if you pass it nonascii */
+ if ((unsigned char)*t > 0x7f) {
+ zwarnnam(name, "no such terminfo capability: %s", s);
+ return 1;
+ }
+ }
/* if the specified capability has a numeric value, display it */
if (((num = tigetnum(s)) != -1) && (num != -2)) {
printf("%d\n", num);
@@ -111,7 +119,7 @@ bin_echoti(char *name, char **argv, UNUSED(Options ops), UNUSED(int func))
/* get the arguments */
for (arg=0; argv[arg]; arg++) {
if (strarg && arg > 0)
- pars[arg] = (long) argv[arg];
+ pars[arg] = (long) unmetafy(dupstring(argv[arg]), NULL);
else
pars[arg] = atoi(argv[arg]);
}
@@ -134,8 +142,9 @@ static struct builtin bintab[] = {
static HashNode
getterminfo(UNUSED(HashTable ht), const char *name)
{
- int len, num;
- char *tistr, *nameu;
+ int num;
+ char *tistr;
+ const char *t;
Param pm = NULL;
/* This depends on the termcap stuff in init.c */
@@ -144,22 +153,26 @@ getterminfo(UNUSED(HashTable ht), const char *name)
if ((termflags & TERM_UNKNOWN) && (isset(INTERACTIVE) || !init_term()))
return NULL;
- nameu = dupstring(name);
- unmetafy(nameu, &len);
+ for (t = name; *t; t++) {
+ /* ncurses helpfully just crashes if you pass it nonascii */
+ if ((unsigned char)*t > 0x7f) {
+ return NULL;
+ }
+ }
pm = (Param) hcalloc(sizeof(struct param));
- pm->node.nam = nameu;
+ pm->node.nam = dupstring(name);
pm->node.flags = PM_READONLY;
- if (((num = tigetnum(nameu)) != -1) && (num != -2)) {
+ if (((num = tigetnum(name)) != -1) && (num != -2)) {
pm->u.val = num;
pm->node.flags |= PM_INTEGER;
pm->gsu.i = &nullsetinteger_gsu;
- } else if ((num = tigetflag(nameu)) != -1) {
+ } else if ((num = tigetflag(name)) != -1) {
pm->u.str = num ? dupstring("yes") : dupstring("no");
pm->node.flags |= PM_SCALAR;
pm->gsu.s = &nullsetscalar_gsu;
- } else if ((tistr = (char *)tigetstr(nameu)) != NULL && tistr != (char *)-1) {
+ } else if ((tistr = (char *)tigetstr(name)) != NULL && tistr != (char *)-1) {
pm->u.str = metafy(tistr, -1, META_HEAPDUP);
pm->node.flags |= PM_SCALAR;
pm->gsu.s = &nullsetscalar_gsu;