Mon Sep 7 06:43:48 2015 UTC ()
On Linux, Bash is fine if you don't mind your package builds spending 50% of
their time compiling, and 50% spinning in shell scripts.  If you'd rather
spend your power bill on useful gcc cycles though, you might desire to use a
different shell for running build scripts - like pdksh, which is conveniently
available at bootstrap time.

But what if pdksh does this to you?

pdksh -c 'f=`pdksh -c set | wc -l`; f=$((f+1)); while ((f < 100000)); do f=$((f+1)); eval "v_${f}=0"; echo "$f"; done'|tail -1
 13106
segmentation fault (core dumped)  pdksh -c

Well that's annoying, isn't it.

% echo $(((13106*10+7)/8))
16383

... that's a magical number.  Coincidence?  Well, no.

tp->nfree = 8*nsize/10; /* table can get 80% full */

This particularly ugly overflow happens because tp->size is a short.  When
texpand() does:

  p = &ntblp[hash(tblp->name) & (tp->size-1)];

tp->size-1 will, given enough variables (80% of 2^15), type coerce into a
sign-extended 32-bit value of:

info registers $ecx
ecx            0xffff7fff       -32769

That hash() function does more or less what you guess, it's a 32 bit unsigned
value.  The chances of the final pointer pointing inside the valid allocated
block of memory are very low indeed.

The least-change solution is to change tp->size to a 32 bit value.  I've left
it signed because that matches, for example, the size parameter passed to
texpand().  But really this code would be more correct with a liberal
sprinkling of "unsigned", and perhaps a bit of "size_t".

This change allows ffmpeg's configure script, as interpreted by pdksh, to
produce more usable output than a core file.

Bump PKGREVISION for code change.


(dsainty)
diff -r1.22 -r1.23 pkgsrc/shells/pdksh/Makefile
diff -r1.2 -r1.3 pkgsrc/shells/pdksh/files/table.h

cvs diff -r1.22 -r1.23 pkgsrc/shells/pdksh/Makefile (expand / switch to unified diff)

--- pkgsrc/shells/pdksh/Makefile 2014/10/09 14:06:56 1.22
+++ pkgsrc/shells/pdksh/Makefile 2015/09/07 06:43:48 1.23
@@ -1,18 +1,18 @@ @@ -1,18 +1,18 @@
1# $NetBSD: Makefile,v 1.22 2014/10/09 14:06:56 wiz Exp $ 1# $NetBSD: Makefile,v 1.23 2015/09/07 06:43:48 dsainty Exp $
2# 2#
3 3
4DISTNAME= pdksh-5.2.14 4DISTNAME= pdksh-5.2.14
5PKGREVISION= 5 5PKGREVISION= 6
6CATEGORIES= shells 6CATEGORIES= shells
7MASTER_SITES= ftp://ftp.cs.mun.ca/pub/pdksh/ \ 7MASTER_SITES= ftp://ftp.cs.mun.ca/pub/pdksh/ \
8 http://gd.tuwien.ac.at/utils/shells/pdksh/ \ 8 http://gd.tuwien.ac.at/utils/shells/pdksh/ \
9 ftp://ftp.lip6.fr/pub/unix/shells/pdksh/ \ 9 ftp://ftp.lip6.fr/pub/unix/shells/pdksh/ \
10 ftp://ftp.demon.net/pub/mirrors/pdksh/ 10 ftp://ftp.demon.net/pub/mirrors/pdksh/
11MASTER_SITES= # maintained locally 11MASTER_SITES= # maintained locally
12DISTFILES= # empty 12DISTFILES= # empty
13 13
14MAINTAINER= schmonz@NetBSD.org 14MAINTAINER= schmonz@NetBSD.org
15HOMEPAGE= http://web.cs.mun.ca/~michael/pdksh/ 15HOMEPAGE= http://web.cs.mun.ca/~michael/pdksh/
16COMMENT= Free clone of the AT&T Korn shell 16COMMENT= Free clone of the AT&T Korn shell
17 17
18BOOTSTRAP_PKG= yes 18BOOTSTRAP_PKG= yes

cvs diff -r1.2 -r1.3 pkgsrc/shells/pdksh/files/table.h (expand / switch to unified diff)

--- pkgsrc/shells/pdksh/files/table.h 2008/05/31 16:47:37 1.2
+++ pkgsrc/shells/pdksh/files/table.h 2015/09/07 06:43:48 1.3
@@ -1,22 +1,22 @@ @@ -1,22 +1,22 @@
1/* $NetBSD: table.h,v 1.2 2008/05/31 16:47:37 tnn Exp $ */ 1/* $NetBSD: table.h,v 1.3 2015/09/07 06:43:48 dsainty Exp $ */
2 2
3/* 3/*
4 * generic hashed associative table for commands and variables. 4 * generic hashed associative table for commands and variables.
5 */ 5 */
6 6
7struct table { 7struct table {
8 Area *areap; /* area to allocate entries */ 8 Area *areap; /* area to allocate entries */
9 short size, nfree; /* hash size (always 2^^n), free entries */ 9 int size, nfree; /* hash size (always 2^^n), free entries */
10 struct tbl **tbls; /* hashed table items */ 10 struct tbl **tbls; /* hashed table items */
11}; 11};
12 12
13struct tbl { /* table item */ 13struct tbl { /* table item */
14 Tflag flag; /* flags */ 14 Tflag flag; /* flags */
15 int type; /* command type (see below), base (if INTEGER), 15 int type; /* command type (see below), base (if INTEGER),
16 * or offset from val.s of value (if EXPORT) */ 16 * or offset from val.s of value (if EXPORT) */
17 Area *areap; /* area to allocate from */ 17 Area *areap; /* area to allocate from */
18 union { 18 union {
19 char *s; /* string */ 19 char *s; /* string */
20 long i; /* integer */ 20 long i; /* integer */
21 int (*f) ARGS((char **)); /* int function */ 21 int (*f) ARGS((char **)); /* int function */
22 struct op *t; /* "function" tree */ 22 struct op *t; /* "function" tree */