Date: Fri, 11 Apr 2008 17:41:59 +0300 (EEST) From: Jaakko Heinonen <jh@saunalahti.fi> To: FreeBSD-gnats-submit@FreeBSD.org Subject: bin/122659: [patch] sh(1) long arithmetics broken on certain architectures Message-ID: <200804111441.m3BEfxYL006720@ws64.jh.dy.fi> Resent-Message-ID: <200804111450.m3BEo19X055991@freefall.freebsd.org>
next in thread | raw e-mail | index | archive | help
>Number: 122659 >Category: bin >Synopsis: [patch] sh(1) long arithmetics broken on certain architectures >Confidential: no >Severity: non-critical >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Fri Apr 11 14:50:00 UTC 2008 >Closed-Date: >Last-Modified: >Originator: Jaakko Heinonen >Release: FreeBSD 7.0-RELEASE amd64 >Organization: >Environment: System: FreeBSD x 7.0-RELEASE FreeBSD 7.0-RELEASE #0: Sun Feb 24 10:35:36 UTC 2008 root@driscoll.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC amd64 >Description: This PR partially supersedes bin/51171. In src/bin/sh/shell.h there's a following comment: /* * Type of used arithmetics. SUSv3 requires us to have at least signed long. */ However in sh(1) code int type is used in several places for arithmetics which prevents long arithmetics to work on architectures where sizeof(int) != sizeof(long). >How-To-Repeat: $ sh -c 'uname -m; echo $((2147483647 + 1))' amd64 -2147483648 >Fix: I have attached two patches here. The first one converts places still using int instead of arith_t to use arith_t. It also converts hardcoded format strings to ARITH_FORMAT_STR and removes the hardcoded limitation of 10 characters for numbers. The second patch which must be applied on top of the first one converts arith_t from long to intmax_t. This patch is not strictly needed to comply with SUS but it extends 32 bit arithmetics to 64 bits for example on i386. --- sh-long-arith.diff begins here --- Index: arith.h =================================================================== RCS file: /home/ncvs/src/bin/sh/arith.h,v retrieving revision 1.11 diff -p -u -r1.11 arith.h --- arith.h 13 Aug 2005 07:59:46 -0000 1.11 +++ arith.h 9 Apr 2008 12:19:06 -0000 @@ -30,8 +30,10 @@ * $FreeBSD: src/bin/sh/arith.h,v 1.11 2005/08/13 07:59:46 stefanf Exp $ */ +#define lstrlen(var) (3 + (2 + CHAR_BIT * sizeof((var))) / 3) + extern char *arith_buf, *arith_startbuf; -int arith(char *); +arith_t arith(char *); void arith_lex_reset(void); int expcmd(int, char **); Index: arith.y =================================================================== RCS file: /home/ncvs/src/bin/sh/arith.y,v retrieving revision 1.21 diff -p -u -r1.21 arith.y --- arith.y 13 Aug 2005 07:59:46 -0000 1.21 +++ arith.y 9 Apr 2008 12:19:06 -0000 @@ -43,8 +43,8 @@ __FBSDID("$FreeBSD: src/bin/sh/arith.y,v #include <limits.h> #include <stdio.h> -#include "arith.h" #include "shell.h" +#include "arith.h" #include "var.h" %} %union { @@ -75,7 +75,10 @@ __FBSDID("$FreeBSD: src/bin/sh/arith.y,v exp: expr - { return ($1); } + { + *(YYPARSE_PARAM) = ($1); + return (0); + } ; expr: @@ -259,12 +262,13 @@ expr: #include "output.h" #include "memalloc.h" -#define lstrlen(var) (3 + (2 + CHAR_BIT * sizeof((var))) / 3) +#define YYPARSE_PARAM_TYPE arith_t * +#define YYPARSE_PARAM result char *arith_buf, *arith_startbuf; int yylex(void); -int yyparse(void); +int yyparse(YYPARSE_PARAM_TYPE); static int arith_assign(char *name, arith_t value) @@ -279,15 +283,15 @@ arith_assign(char *name, arith_t value) return ret; } -int +arith_t arith(char *s) { - long result; + arith_t result; arith_buf = arith_startbuf = s; INTOFF; - result = yyparse(); + yyparse(&result); arith_lex_reset(); /* Reprime lex. */ INTON; @@ -313,7 +317,7 @@ expcmd(int argc, char **argv) char *p; char *concat; char **ap; - long i; + arith_t i; if (argc > 1) { p = argv[1]; @@ -338,8 +342,8 @@ expcmd(int argc, char **argv) i = arith(p); - out1fmt("%ld\n", i); - return !i; + out1fmt(ARITH_FORMAT_STR "\n", i); + return ((int)!i); } /*************************/ Index: arith_lex.l =================================================================== RCS file: /home/ncvs/src/bin/sh/arith_lex.l,v retrieving revision 1.24 diff -p -u -r1.24 arith_lex.l --- arith_lex.l 13 Aug 2005 07:59:46 -0000 1.24 +++ arith_lex.l 9 Apr 2008 12:19:06 -0000 @@ -42,8 +42,8 @@ __FBSDID("$FreeBSD: src/bin/sh/arith_lex #include <string.h> -#include "arith.h" #include "shell.h" +#include "arith.h" #include "y.tab.h" #include "error.h" #include "memalloc.h" Index: expand.c =================================================================== RCS file: /home/ncvs/src/bin/sh/expand.c,v retrieving revision 1.51 diff -p -u -r1.51 expand.c --- expand.c 7 Nov 2006 22:46:13 -0000 1.51 +++ expand.c 9 Apr 2008 12:19:06 -0000 @@ -356,7 +356,7 @@ void expari(int flag) { char *p, *start; - int result; + arith_t result; int begoff; int quotes = flag & (EXP_FULL | EXP_CASE | EXP_REDIR); int quoted; @@ -372,10 +372,7 @@ expari(int flag) * have to rescan starting from the beginning since CTLESC * 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); + CHECKSTRSPACE(lstrlen(result) - 2, expdest); USTPUTC('\0', expdest); start = stackblock(); p = expdest - 2; @@ -397,7 +394,7 @@ expari(int flag) if (quotes) rmescapes(p+2); result = arith(p+2); - fmtstr(p, 12, "%d", result); + fmtstr(p, lstrlen(result), ARITH_FORMAT_STR, result); while (*p++) ; if (quoted == 0) --- sh-long-arith.diff ends here --- --- sh-arith-intmax_t.diff begins here --- --- sh/shell.h 2008-04-09 13:10:06.000000000 +0300 +++ sh/shell.h 2008-04-09 13:16:03.000000000 +0300 @@ -33,6 +33,8 @@ * $FreeBSD: src/bin/sh/shell.h,v 1.17 2004/04/06 20:06:51 markm Exp $ */ +#include <inttypes.h> + /* * The follow should be set to reflect the type of system you have: * JOBS -> 1 if you have Berkeley job control, 0 otherwise. @@ -50,10 +52,10 @@ /* * Type of used arithmetics. SUSv3 requires us to have at least signed long. */ -typedef long arith_t; -#define ARITH_FORMAT_STR "%ld" -#define atoarith_t(arg) strtol(arg, NULL, 0) -#define strtoarith_t(nptr, endptr, base) strtol(nptr, endptr, base) +typedef intmax_t arith_t; +#define ARITH_FORMAT_STR "%" PRIdMAX +#define atoarith_t(arg) strtoimax(arg, NULL, 0) +#define strtoarith_t(nptr, endptr, base) strtoimax(nptr, endptr, base) typedef void *pointer; #define STATIC static --- sh-arith-intmax_t.diff ends here --- >Release-Note: >Audit-Trail: >Unformatted:
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200804111441.m3BEfxYL006720>