Re: /bin/sh and 32-bit arithmetics [CORRECTED]

From: Alex Semenyaka <alexs_at_ratmir.ru>
Date: Sun, 20 Apr 2003 05:34:00 +0400
...ghmmm... sorry and sorry... and here the patch, it is pretty small:

diff -u -r -U 2 -b ../sh.old/Makefile ./Makefile
--- ../sh.old/Makefile	Sat Apr 19 23:22:31 2003
+++ ./Makefile	Sun Apr 20 02:47:41 2003
_at__at_ -19,5 +19,5 _at__at_
 
 LFLAGS= -8	# 8-bit lex scanner for arithmetic
-CFLAGS+=-DSHELL -I. -I${.CURDIR}
+CFLAGS+=-DSHELL -I. -I${.CURDIR} -DOVERFLOW
 # for debug:
 #CFLAGS+= -g -DDEBUG=2 -pg
diff -u -r -U 2 -b ../sh.old/arith.h ./arith.h
--- ../sh.old/arith.h	Fri Jul 19 08:38:51 2002
+++ ./arith.h	Sun Apr 20 02:37:37 2003
_at__at_ -35,4 +35,7 _at__at_
  */
 
-int arith(char *);
+/* XXX some day probably should go to /usr/include/machine/_inttypes.h */
+#define MAXINT_LEN 20
+
+intmax_t arith(char *);
 int expcmd(int , char **);
diff -u -r -U 2 -b ../sh.old/arith.y ./arith.y
--- ../sh.old/arith.y	Fri Jul 19 08:38:51 2002
+++ ./arith.y	Sun Apr 20 03:52:31 2003
_at__at_ -1,2 +1,13 _at__at_
+%{
+#include <stdint.h>
+#ifdef OVERFLOW
+#include "options.h"
+#endif
+
+#define YYSTYPE intmax_t
+
+static intmax_t arith_res;
+%}
+
 %token ARITH_NUM ARITH_LPAREN ARITH_RPAREN
 
_at__at_ -15,5 +26,6 _at__at_
 
 exp:	expr = {
-			return ($1);
+			arith_res = $1;
+			return (0);
 		}
 	;
_at__at_ -34,7 +46,25 _at__at_
 	| expr ARITH_LSHIFT expr = { $$ = $1 << $3; }
 	| expr ARITH_RSHIFT expr = { $$ = $1 >> $3; }
-	| expr ARITH_ADD expr	= { $$ = $1 + $3; }
-	| expr ARITH_SUB expr	= { $$ = $1 - $3; }
-	| expr ARITH_MUL expr	= { $$ = $1 * $3; }
+	| expr ARITH_ADD expr	= {
+				    $$ = $1 + $3;
+#ifdef OVERFLOW
+				    if (Oflag && is_add_overflow($1, $3, $$))
+					yyerror("overflow in");
+#endif
+				  }
+	| expr ARITH_SUB expr	= {
+				    $$ = $1 - $3;
+#ifdef OVERFLOW
+				    if (Oflag && is_add_overflow($1, -$3, $$))
+					yyerror("overflow in");
+#endif
+				  }
+	| expr ARITH_MUL expr	= {
+				    $$ = $1 * $3;
+#ifdef OVERFLOW
+				    if (Oflag && $$/$1 != $3 )
+					yyerror("overflow in");
+#endif
+				  }
 	| expr ARITH_DIV expr	= {
 			if ($3 == 0)
_at__at_ -110,16 +140,24 _at__at_
 
 int
-arith(char *s)
+is_add_overflow(intmax_t a, intmax_t b, intmax_t s)
 {
-	long result;
+ if (a > 0 && b > 0 && s <= 0)
+	return 1;
+ if (a < 0 && b < 0 && s >= 0)
+	return 1;
+ return 0;
+}
 
+intmax_t
+arith(char *s)
+{
 	arith_buf = arith_startbuf = s;
 
 	INTOFF;
-	result = yyparse();
+	yyparse();
 	arith_lex_reset();	/* reprime lex */
 	INTON;
 
-	return (result);
+	return (arith_res);
 }
 
_at__at_ -143,5 +181,5 _at__at_
 	char *concat;
 	char **ap;
-	long i;
+	intmax_t i;
 
 	if (argc > 1) {
_at__at_ -168,5 +206,5 _at__at_
 	i = arith(p);
 
-	out1fmt("%ld\n", i);
+	out1fmt("%jd\n", i);
 	return (! i);
 }
diff -u -r -U 2 -b ../sh.old/arith_lex.l ./arith_lex.l
--- ../sh.old/arith_lex.l	Fri Jul 19 08:38:51 2002
+++ ./arith_lex.l	Sun Apr 20 02:37:37 2003
_at__at_ -44,8 +44,9 _at__at_
 #endif /* not lint */
 
+#include <stdint.h>
 #include "y.tab.h"
 #include "error.h"
 
-extern int yylval;
+extern intmax_t yylval;
 extern char *arith_buf, *arith_startbuf;
 #undef YY_INPUT
_at__at_ -57,5 +58,5 _at__at_
 %%
 [ \t\n]	{ ; }
-[0-9]+	{ yylval = atol(yytext); return(ARITH_NUM); }
+[0-9]+	{ yylval = strtoll(yytext, NULL, 10); return(ARITH_NUM); }
 "("	{ return(ARITH_LPAREN); }
 ")"	{ return(ARITH_RPAREN); }
diff -u -r -U 2 -b ../sh.old/expand.c ./expand.c
--- ../sh.old/expand.c	Fri Jan 17 14:37:03 2003
+++ ./expand.c	Sun Apr 20 02:37:37 2003
_at__at_ -46,4 +46,5 _at__at_
 #include <sys/time.h>
 #include <sys/stat.h>
+#include <stdint.h>
 #include <errno.h>
 #include <dirent.h>
_at__at_ -367,5 +368,5 _at__at_
 {
 	char *p, *start;
-	int result;
+	intmax_t result;
 	int begoff;
 	int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
_at__at_ -383,8 +384,8 _at__at_
 	 * characters have to be processed left to right.
 	 */
-#if INT_MAX / 1000000000 >= 10 || INT_MIN / 1000000000 <= -10
-#error "integers with more than 10 digits are not supported"
-#endif
-	CHECKSTRSPACE(12 - 2, expdest);
+//#if INT_MAX / 1000000000 >= 10 || INT_MIN / 1000000000 <= -10
+//#error "integers with more than 10 digits are not supported"
+//#endif
+	CHECKSTRSPACE(MAXINT_LEN, expdest);
 	USTPUTC('\0', expdest);
 	start = stackblock();
_at__at_ -408,5 +409,5 _at__at_
 		rmescapes(p+2);
 	result = arith(p+2);
-	fmtstr(p, 12, "%d", result);
+	fmtstr(p, MAXINT_LEN + 2, "%qd", result);
 	while (*p++)
 		;
diff -u -r -U 2 -b ../sh.old/options.h ./options.h
--- ../sh.old/options.h	Tue Aug 27 05:36:28 2002
+++ ./options.h	Sun Apr 20 02:24:46 2003
_at__at_ -67,6 +67,13 _at__at_
 #define	Tflag optlist[16].val
 #define	Pflag optlist[17].val
+#ifdef OVERFLOW
+#define	Oflag optlist[18].val
+#endif
 
+#ifdef OVERFLOW
+#define NOPTS	19
+#else
 #define NOPTS	18
+#endif
 
 struct optent {
_at__at_ -96,4 +103,7 _at__at_
 	{ "trapsasync",	'T',	0 },
 	{ "physical",	'P',	0 },
+#ifdef OVERFLOW
+	{ "overflow",	'O',	0 },
+#endif
 };
 #else
diff -u -r -U 2 -b ../sh.old/sh.1 ./sh.1
--- ../sh.old/sh.1	Tue Feb 25 13:27:12 2003
+++ ./sh.1	Sun Apr 20 02:52:02 2003
_at__at_ -44,5 +44,5 _at__at_
 .Sh SYNOPSIS
 .Nm
-.Op Fl /+abCEefIimnPpsTuVvx
+.Op Fl /+abCEefIimnOPpsTuVvx
 .Op Fl /+o Ar longname
 .Op Fl c Ar string
_at__at_ -226,4 +226,6 _at__at_
 execute them.  This is useful for checking the
 syntax of shell scripts.
+.It Fl O Li interactive
+If compiled with the overflow checks, turn them during arithmetic operations on.
 .It Fl P Li physical
 Change the default for the
Received on Sat Apr 19 2003 - 16:34:05 UTC

This archive was generated by hypermail 2.4.0 : Wed May 19 2021 - 11:37:04 UTC