[hackers] [sbase][PATCH] ls and xargs: Reduce sbase-box static bss memory usage

From: Xan Phung <xan.phung_AT_gmail.com>
Date: Wed, 4 Jun 2025 14:40:41 +1000

These two tools use large static buffers. In sbase-box, 146Kb is
always allocated for them, even if they are not the tool being run.

This patch changes their buffer allocation to use the stack instead
of static memory. The bss size of sbase-box is reduced from 179Kb
to 33Kb. Test scripts are provided for regression testing.
---
 ls.c                      |  6 +++--
 tests/ls-R.sh             | 17 ++++++++++++++
 tests/ls-R.sh.expected    | 48 +++++++++++++++++++++++++++++++++++++++
 tests/xargs-n.sh          | 10 ++++++++
 tests/xargs-n.sh.expected |  5 ++++
 xargs.c                   | 10 ++++----
 6 files changed, 89 insertions(+), 7 deletions(-)
 create mode 100755 tests/ls-R.sh
 create mode 100644 tests/ls-R.sh.expected
 create mode 100755 tests/xargs-n.sh
 create mode 100644 tests/xargs-n.sh.expected
diff --git a/ls.c b/ls.c
index aa95fef..869ecd1 100644
--- a/ls.c
+++ b/ls.c
_AT_@ -30,10 +30,10 @@ struct entry {
 	ino_t   ino, tino;
 };
 
-static struct {
+static struct tree {
 	dev_t dev;
 	ino_t ino;
-} tree[PATH_MAX];
+} *tree;
 
 static int ret   = 0;
 static int Aflag = 0;
_AT_@ -369,7 +369,9 @@ int
 main(int argc, char *argv[])
 {
 	struct entry ent, *dents, *fents;
+	struct tree treebuf[PATH_MAX] = {0};
 	size_t i, ds, fs;
+	tree = treebuf;
 
 	ARGBEGIN {
 	case '1':
diff --git a/tests/ls-R.sh b/tests/ls-R.sh
new file mode 100755
index 0000000..df70551
--- /dev/null
+++ b/tests/ls-R.sh
_AT_@ -0,0 +1,17 @@
+#!/bin/sh
+TESTEXE="${TESTEXE:-../../ls}"
+TESTARG="-R"
+TESTINP=""
+
+mkdir -p ls-R.tmp || exit 2
+cd ls-R.tmp || exit 2
+mkdir -p test1 test2 test4 test5 test2/sub1 test2/sub2 || exit 2
+touch testfile test2/sub1/file1 test2/sub1/file2 || exit 2
+command -v "$TESTEXE" >/dev/null || exit 127
+"$TESTEXE" $TESTARG >"../$0.out" 2>&1 test2 test3 test4 || fail=1
+"$TESTEXE" $TESTARG >>"../$0.out" 2>&1 test4 test5 testfile || fail=1
+"$TESTEXE" $TESTARG >>"../$0.out" 2>&1 . || fail=1
+cd ..
+cmp "$0.expected" "$0.out" || fail=1
+exit $fail
+
diff --git a/tests/ls-R.sh.expected b/tests/ls-R.sh.expected
new file mode 100644
index 0000000..757eba2
--- /dev/null
+++ b/tests/ls-R.sh.expected
_AT_@ -0,0 +1,48 @@
+test2:
+sub1
+sub2
+
+test2/sub1:
+file1
+file2
+
+test2/sub2:
+
+test3:
+sub1
+sub2
+
+test3/sub1:
+file1
+file2
+
+test3/sub2:
+
+test4:
+testfile
+
+test4:
+
+test5:
+test1
+test2
+test3
+test4
+test5
+testfile
+
+./test1:
+
+./test2:
+sub1
+sub2
+
+./test2/sub1:
+file1
+file2
+
+./test2/sub2:
+
+./test4:
+
+./test5:
diff --git a/tests/xargs-n.sh b/tests/xargs-n.sh
new file mode 100755
index 0000000..a0c292c
--- /dev/null
+++ b/tests/xargs-n.sh
_AT_@ -0,0 +1,10 @@
+#!/bin/sh
+TESTEXE="${TESTEXE:-../xargs}"
+TESTARG="-n3"
+TESTINP="aaaa bbb c\nddd eeee\nfffffff\nggggg h iiii\nj k l\na bbb"
+
+command -v "$TESTEXE" >/dev/null || exit 127
+printf "$TESTINP" | "$TESTEXE" $TESTARG >"$0.out" 2>&1 || fail=1
+cmp "$0.expected" "$0.out" || fail=1
+exit $fail
+
diff --git a/tests/xargs-n.sh.expected b/tests/xargs-n.sh.expected
new file mode 100644
index 0000000..f2cc442
--- /dev/null
+++ b/tests/xargs-n.sh.expected
_AT_@ -0,0 +1,5 @@
+aaaa bbb c
+ddd eeee fffffff
+ggggg h iiii
+j k l
+a bbb
diff --git a/xargs.c b/xargs.c
index d9b2d98..cc48772 100644
--- a/xargs.c
+++ b/xargs.c
_AT_@ -20,7 +20,7 @@ static int parsequote(int);
 static int parseescape(void);
 static char *poparg(void);
 static void waitchld(void);
-static void spawn(void);
+static void spawn(char **);
 
 static size_t argbsz;
 static size_t argbpos;
_AT_@ -28,7 +28,6 @@ static size_t maxargs = 0;
 static int    nerrors = 0;
 static int    rflag = 0, nflag = 0, tflag = 0, xflag = 0, Iflag = 0;
 static char  *argb;
-static char  *cmd[NARGS];
 static char  *eofstr;
 
 static int
_AT_@ -162,7 +161,7 @@ waitchld(void)
 }
 
 static void
-spawn(void)
+spawn(char *cmd[])
 {
 	int savederrno;
 	int first = 1;
_AT_@ -203,6 +202,7 @@ main(int argc, char *argv[])
 	int ret = 0, leftover = 0, i, j;
 	size_t argsz, argmaxsz;
 	size_t arglen, a;
+	char *cmd[NARGS];
 	char *arg = "";
 	char *replstr;
 
_AT_@ -287,11 +287,11 @@ main(int argc, char *argv[])
 		}
 		cmd[i] = NULL;
 		if (a >= maxargs && nflag)
-			spawn();
+			spawn(cmd);
 		else if (!a || (i == 1 && rflag))
 			;
 		else
-			spawn();
+			spawn(cmd);
 		for (; i >= 0; i--)
 			free(cmd[i]);
 	} while (arg);
-- 
2.49.0
Received on Wed Jun 04 2025 - 06:40:41 CEST

This archive was generated by hypermail 2.3.0 : Wed Jun 04 2025 - 07:00:38 CEST