Date: Sun, 20 Apr 2003 05:34:00 +0400 From: Alex Semenyaka <alexs@ratmir.ru> To: Alex Semenyaka <alexs@snark.ratmir.ru> Cc: freebsd-standards@freebsd.org Subject: Re: /bin/sh and 32-bit arithmetics [CORRECTED] Message-ID: <20030420013400.GB52428@snark.ratmir.ru> In-Reply-To: <20030420011039.GC52081@snark.ratmir.ru> References: <20030420011039.GC52081@snark.ratmir.ru>
next in thread | previous in thread | raw e-mail | index | archive | help
...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
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20030420013400.GB52428>