vi is kind of weird about COLUMNS/LINES handling.
For one, it doesn't do any error checking:
$ COLUMNS=a vi
Floating point exception (core dumped)
The manpage also claims that COLUMNS supersedes everything else. This
is true... unless you ^Z and then unsuspend, at which point it uses
TIOCGWINSZ.
And then it has to handle :set columns, which it does by setting
environment variables and immediately unsetting them...
Maybe I just don't get it, but it all seems very complicated. For
the time being here's a diff to at least add error checking so COLUMNS
can't crash the program. Kept as strtol() since patches still flow
between our vi and sundry forks.
ok?
Index: cl/cl_term.c
===================================================================
RCS file: /cvs/src/usr.bin/vi/cl/cl_term.c,v
retrieving revision 1.21
diff -u -p -r1.21 cl_term.c
--- cl/cl_term.c 6 Jan 2016 22:28:52 -0000 1.21
+++ cl/cl_term.c 14 Mar 2016 07:38:41 -0000
@@ -319,7 +319,8 @@ cl_ssize(SCR *sp, int sigwinch, size_t *
struct winsize win;
size_t col, row;
int rval;
- char *p;
+ long lval;
+ char *p, *ep;
/* Assume it's changed. */
if (changedp != NULL)
@@ -413,10 +414,28 @@ noterm: if (row == 0)
* deleting the LINES and COLUMNS environment variables from their
* dot-files.
*/
- if ((p = getenv("LINES")) != NULL)
- row = strtol(p, NULL, 10);
- if ((p = getenv("COLUMNS")) != NULL)
- col = strtol(p, NULL, 10);
+ if ((p = getenv("LINES")) != NULL) {
+ errno = 0;
+ lval = strtol(p, &ep, 10);
+ if (p[0] == '\0' || *ep != '\0')
+ ;
+ else if ((errno == ERANGE && (lval == LONG_MAX || lval ==
+ LONG_MIN)) || (lval > INT_MAX || lval < 1))
+ ;
+ else
+ row = lval;
+ }
+ if ((p = getenv("COLUMNS")) != NULL) {
+ errno = 0;
+ lval = strtol(p, &ep, 10);
+ if (p[0] == '\0' || *ep != '\0')
+ ;
+ else if ((errno == ERANGE && (lval == LONG_MAX || lval ==
+ LONG_MIN)) || (lval > INT_MAX || lval < 1))
+ ;
+ else
+ col = lval;
+ }
if (rowp != NULL)
*rowp = row;