bin/122659: [patch] sh(1) long arithmetics broken on certain
architectures
Jaakko Heinonen
jh at saunalahti.fi
Fri Apr 11 14:50:01 UTC 2008
>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 at 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:
More information about the freebsd-bugs
mailing list