/bin/sh and 32-bit arithmetics [CORRECTED]
Alex Semenyaka
alexs at ratmir.ru
Sat Apr 19 18:34:06 PDT 2003
...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
@@ -19,5 +19,5 @@
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
@@ -35,4 +35,7 @@
*/
-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
@@ -1,2 +1,13 @@
+%{
+#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
@@ -15,5 +26,6 @@
exp: expr = {
- return ($1);
+ arith_res = $1;
+ return (0);
}
;
@@ -34,7 +46,25 @@
| 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)
@@ -110,16 +140,24 @@
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);
}
@@ -143,5 +181,5 @@
char *concat;
char **ap;
- long i;
+ intmax_t i;
if (argc > 1) {
@@ -168,5 +206,5 @@
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
@@ -44,8 +44,9 @@
#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
@@ -57,5 +58,5 @@
%%
[ \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
@@ -46,4 +46,5 @@
#include <sys/time.h>
#include <sys/stat.h>
+#include <stdint.h>
#include <errno.h>
#include <dirent.h>
@@ -367,5 +368,5 @@
{
char *p, *start;
- int result;
+ intmax_t result;
int begoff;
int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR);
@@ -383,8 +384,8 @@
* 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();
@@ -408,5 +409,5 @@
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
@@ -67,6 +67,13 @@
#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 {
@@ -96,4 +103,7 @@
{ "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
@@ -44,5 +44,5 @@
.Sh SYNOPSIS
.Nm
-.Op Fl /+abCEefIimnPpsTuVvx
+.Op Fl /+abCEefIimnOPpsTuVvx
.Op Fl /+o Ar longname
.Op Fl c Ar string
@@ -226,4 +226,6 @@
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
More information about the freebsd-hackers
mailing list