Module Name:    src
Committed By:   rillig
Date:           Sun Jan 15 15:20:18 UTC 2023

Modified Files:
        src/usr.bin/xlint/xlint: xlint.c

Log Message:
lint: turn O(n^2) to O(n) for list of arguments to lint child processes

Previously, adding an argument to the lint child processes (cpp, lint1,
lint2) each time searched the list of arguments for the terminating
null pointer and then reallocated the memory for storing the strings.

Replace the above with a standard resizable array implementation and
give it a proper name, to avoid 'char ***' in the code.

The terminating null pointer in the lists is only required when passing
the list to execvp.  In all other cases it's not needed, so drop it.

No functional change.


To generate a diff of this commit:
cvs rdiff -u -r1.98 -r1.99 src/usr.bin/xlint/xlint/xlint.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/usr.bin/xlint/xlint/xlint.c
diff -u src/usr.bin/xlint/xlint/xlint.c:1.98 src/usr.bin/xlint/xlint/xlint.c:1.99
--- src/usr.bin/xlint/xlint/xlint.c:1.98	Sun Jan 15 14:43:39 2023
+++ src/usr.bin/xlint/xlint/xlint.c	Sun Jan 15 15:20:18 2023
@@ -1,4 +1,4 @@
-/* $NetBSD: xlint.c,v 1.98 2023/01/15 14:43:39 rillig Exp $ */
+/* $NetBSD: xlint.c,v 1.99 2023/01/15 15:20:18 rillig Exp $ */
 
 /*
  * Copyright (c) 1996 Christopher G. Demetriou.  All Rights Reserved.
@@ -38,7 +38,7 @@
 
 #include <sys/cdefs.h>
 #if defined(__RCSID)
-__RCSID("$NetBSD: xlint.c,v 1.98 2023/01/15 14:43:39 rillig Exp $");
+__RCSID("$NetBSD: xlint.c,v 1.99 2023/01/15 15:20:18 rillig Exp $");
 #endif
 
 #include <sys/param.h>
@@ -62,25 +62,31 @@ __RCSID("$NetBSD: xlint.c,v 1.98 2023/01
 
 #define DEFAULT_PATH		_PATH_DEFPATH
 
+typedef struct {
+	char	**items;
+	size_t	len;
+	size_t	cap;
+} list;
+
 /* Parameters for the C preprocessor. */
 static struct {
-	char	**flags;	/* flags always passed */
-	char	**lcflags;	/* flags, controlled by sflag/tflag */
+	list	flags;		/* flags always passed */
+	list	lcflags;	/* flags, controlled by sflag/tflag */
 	char	*outfile;	/* path name for preprocessed C source */
 	int	outfd;		/* file descriptor for outfile */
-} cpp = { NULL, NULL, NULL, -1 };
+} cpp = { .outfd = -1 };
 
 /* Parameters for lint1, which checks an isolated translation unit. */
 static struct {
-	char	**flags;
-	char	**outfiles;
+	list	flags;
+	list	outfiles;
 } lint1;
 
 /* Parameters for lint2, which performs cross-translation-unit checks. */
 static struct {
-	char	**flags;
-	char	**infiles;	/* input files (without libraries) */
-	char	**inlibs;	/* input libraries */
+	list	flags;
+	list	infiles;	/* input files (without libraries) */
+	list	inlibs;		/* input libraries */
 	char	*outlib;	/* output library that will be created */
 } lint2;
 
@@ -88,13 +94,13 @@ static struct {
 static	const char *tmpdir;
 
 /* default libraries */
-static	char	**deflibs;
+static	list	deflibs;
 
 /* additional libraries */
-static	char	**libs;
+static	list	libs;
 
 /* search path for libraries */
-static	char	**libsrchpath;
+static	list	libsrchpath;
 
 static const char *libexec_dir;
 
@@ -122,84 +128,54 @@ static	const	char *currfn;
 static const char target_prefix[] = TARGET_PREFIX;
 
 static	void	fname(const char *);
-static	void	run_child(const char *, char *const *, const char *, int);
-static	void	find_libs(char *const *);
+static	void	run_child(const char *, list *, const char *, int);
+static	void	find_libs(const list *);
 static	bool	file_is_readable(const char *);
 static	void	run_lint2(void);
-static	void	cat(char *const *, const char *);
-
-static char **
-list_new(void)
-{
-	char **list;
-
-	list = xcalloc(1, sizeof(*list));
-	return list;
-}
+static	void	cat(const list *, const char *);
 
 static void
-list_add_ref(char ***lstp, char *s)
+list_add_ref(list *l, char *s)
 {
-	char	**lst, **olst;
-	int	i;
 
-	olst = *lstp;
-	for (i = 0; olst[i] != NULL; i++)
-		continue;
-	lst = xrealloc(olst, (i + 2) * sizeof(*lst));
-	lst[i] = s;
-	lst[i + 1] = NULL;
-	*lstp = lst;
+	if (l->len >= l->cap) {
+		l->cap = 2 * l->len + 16;
+		l->items = xrealloc(l->items, sizeof(*l->items) * l->cap);
+	}
+	l->items[l->len++] = s;
 }
 
 static void
-list_add(char ***lstp, const char *s)
+list_add(list *l, const char *s)
 {
 
-	list_add_ref(lstp, xstrdup(s));
+	list_add_ref(l, xstrdup(s));
 }
 
 static void
-list_add_unique(char ***lstp, const char *s)
+list_add_unique(list *l, const char *s)
 {
 
-	for (char **p = *lstp; *p != NULL; p++)
-		if (strcmp(*p, s) == 0)
+	for (size_t i = 0; i < l->len; i++)
+		if (strcmp(l->items[i], s) == 0)
 			return;
-	list_add(lstp, s);
+	list_add(l, s);
 }
 
 static void
-list_add_all(char ***destp, char *const *src)
+list_add_all(list *dst, const list *src)
 {
-	int	i, k;
-	char	**dest, **odest;
 
-	odest = *destp;
-	for (i = 0; odest[i] != NULL; i++)
-		continue;
-	for (k = 0; src[k] != NULL; k++)
-		continue;
-	dest = xrealloc(odest, (i + k + 1) * sizeof(*dest));
-	for (k = 0; src[k] != NULL; k++)
-		dest[i + k] = xstrdup(src[k]);
-	dest[i + k] = NULL;
-	*destp = dest;
+	for (size_t i = 0; i < src->len; i++)
+		list_add(dst, src->items[i]);
 }
 
 static void
-list_clear(char ***lstp)
+list_clear(list *l)
 {
-	char	*s;
-	int	i;
 
-	for (i = 0; (*lstp)[i] != NULL; i++)
-		continue;
-	while (i-- > 0) {
-		s = (*lstp)[i];
-		(*lstp)[i] = NULL;
-		free(s);
-	}
+	while (l->len > 0)
+		free(l->items[--l->len]);
 }
 
 static void
@@ -256,7 +232,6 @@ concat2(const char *s1, const char *s2)
 static void __attribute__((__noreturn__))
 terminate(int signo)
 {
-	int	i;
 
 	if (cpp.outfd != -1)
 		(void)close(cpp.outfd);
@@ -268,10 +243,8 @@ terminate(int signo)
 			(void)remove(cpp.outfile);
 	}
 
-	if (lint1.outfiles != NULL) {
-		for (i = 0; lint1.outfiles[i] != NULL; i++)
-			(void)remove(lint1.outfiles[i]);
-	}
+	for (size_t i = 0; i < lint1.outfiles.len; i++)
+		(void)remove(lint1.outfiles.items[i]);
 
 	if (lint2.outlib != NULL)
 		(void)remove(lint2.outlib);
@@ -357,17 +330,6 @@ main(int argc, char *argv[])
 		terminate(-1);
 	}
 
-	lint1.outfiles = list_new();
-	lint2.infiles = list_new();
-	cpp.flags = list_new();
-	cpp.lcflags = list_new();
-	lint1.flags = list_new();
-	lint2.flags = list_new();
-	lint2.inlibs = list_new();
-	deflibs = list_new();
-	libs = list_new();
-	libsrchpath = list_new();
-
 	pass_to_cpp("-E");
 	pass_to_cpp("-x");
 	pass_to_cpp("c");
@@ -435,7 +397,7 @@ main(int argc, char *argv[])
 			break;
 
 		case 'p':
-			if (*deflibs != NULL) {
+			if (deflibs.len > 0) {
 				list_clear(&deflibs);
 				list_add(&deflibs, "c");
 			}
@@ -569,23 +531,23 @@ main(int argc, char *argv[])
 		const char *arg = argv[0];
 
 		if (arg[0] == '-') {
-			char ***list;
+			list *lp;
 
 			/* option */
 			if (arg[1] == 'l')
-				list = &libs;
+				lp = &libs;
 			else if (arg[1] == 'L')
-				list = &libsrchpath;
+				lp = &libsrchpath;
 			else {
 				usage("Unknown late option '%s'", arg);
 				/* NOTREACHED */
 			}
 
 			if (arg[2] != '\0')
-				list_add_unique(list, arg + 2);
+				list_add_unique(lp, arg + 2);
 			else if (argc > 1) {
 				argc--;
-				list_add_unique(list, *++argv);
+				list_add_unique(lp, *++argv);
 			} else
 				usage("Missing argument for l or L");
 		} else {
@@ -607,14 +569,14 @@ main(int argc, char *argv[])
 		if ((ks = getenv("LIBDIR")) == NULL || strlen(ks) == 0)
 			ks = PATH_LINTLIB;
 		list_add(&libsrchpath, ks);
-		find_libs(libs);
-		find_libs(deflibs);
+		find_libs(&libs);
+		find_libs(&deflibs);
 	}
 
 	run_lint2();
 
 	if (oflag)
-		cat(lint2.infiles, outputfn);
+		cat(&lint2.infiles, outputfn);
 
 	if (Cflag)
 		lint2.outlib = NULL;
@@ -630,9 +592,8 @@ main(int argc, char *argv[])
 static void
 fname(const char *name)
 {
-	const	char *bn, *suff;
-	char	**args, *ofn, *pathname;
-	const char *CC;
+	const	char *bn, *suff, *CC;
+	char	*ofn, *pathname;
 	size_t	len;
 	int	fd;
 
@@ -675,8 +636,6 @@ fname(const char *name)
 	if (!iflag)
 		list_add(&lint1.outfiles, ofn);
 
-	args = list_new();
-
 	/* run cc */
 	if ((CC = getenv("CC")) == NULL)
 		CC = DEFAULT_CC;
@@ -688,9 +647,10 @@ fname(const char *name)
 		exit(EXIT_FAILURE);
 	}
 
+	list args = { NULL, 0, 0 };
 	list_add(&args, pathname);
-	list_add_all(&args, cpp.flags);
-	list_add_all(&args, cpp.lcflags);
+	list_add_all(&args, &cpp.flags);
+	list_add_all(&args, &cpp.lcflags);
 	list_add(&args, name);
 
 	/* we reuse the same tmp file for cpp output, so rewind and truncate */
@@ -703,7 +663,7 @@ fname(const char *name)
 		terminate(-1);
 	}
 
-	run_child(pathname, args, cpp.outfile, cpp.outfd);
+	run_child(pathname, &args, cpp.outfile, cpp.outfd);
 	free(pathname);
 	list_clear(&args);
 
@@ -721,18 +681,16 @@ fname(const char *name)
 	}
 
 	list_add(&args, pathname);
-	list_add_all(&args, lint1.flags);
+	list_add_all(&args, &lint1.flags);
 	list_add(&args, cpp.outfile);
 	list_add(&args, ofn);
 
-	run_child(pathname, args, ofn, -1);
+	run_child(pathname, &args, ofn, -1);
 	free(pathname);
 	list_clear(&args);
 
 	list_add(&lint2.infiles, ofn);
 	free(ofn);
-
-	free(args);
 }
 
 static bool
@@ -769,15 +727,15 @@ needs_quoting:
 }
 
 static void
-run_child(const char *path, char *const *args, const char *crfn, int fdout)
+run_child(const char *path, list *args, const char *crfn, int fdout)
 {
-	int	status, rv, signo, i;
+	int	status, rv, signo;
 
 	if (Vflag) {
-		print_sh_quoted(args[0]);
-		for (i = 1; args[i] != NULL; i++) {
+		print_sh_quoted(args->items[0]);
+		for (size_t i = 1; i < args->len; i++) {
 			(void)printf(" ");
-			print_sh_quoted(args[i]);
+			print_sh_quoted(args->items[i]);
 		}
 		(void)printf("\n");
 	}
@@ -802,7 +760,9 @@ run_child(const char *path, char *const 
 			(void)dup2(fdout, STDOUT_FILENO);
 			(void)close(fdout);
 		}
-		(void)execvp(path, args);
+		list_add_ref(args, NULL);
+		(void)execvp(path, args->items);
+		args->len--;
 		warn("cannot exec %s", path);
 		_exit(1);
 		/* NOTREACHED */
@@ -830,16 +790,16 @@ run_child(const char *path, char *const 
 static void
 findlib(const char *lib)
 {
-	char *const *dir;
 	char *lfn;
 
-	for (dir = libsrchpath; *dir != NULL; dir++) {
-		lfn = xasprintf("%s/llib-l%s.ln", *dir, lib);
+	for (size_t i = 0; i < libsrchpath.len; i++) {
+		const char *dir = libsrchpath.items[i];
+		lfn = xasprintf("%s/llib-l%s.ln", dir, lib);
 		if (file_is_readable(lfn))
 			goto found;
 		free(lfn);
 
-		lfn = xasprintf("%s/lint/llib-l%s.ln", *dir, lib);
+		lfn = xasprintf("%s/lint/llib-l%s.ln", dir, lib);
 		if (file_is_readable(lfn))
 			goto found;
 		free(lfn);
@@ -854,12 +814,11 @@ found:
 }
 
 static void
-find_libs(char *const *liblst)
+find_libs(const list *l)
 {
-	char *const *p;
 
-	for (p = liblst; *p != NULL; p++)
-		findlib(*p);
+	for (size_t i = 0; i < l->len; i++)
+		findlib(l->items[i]);
 }
 
 static bool
@@ -879,9 +838,7 @@ file_is_readable(const char *path)
 static void
 run_lint2(void)
 {
-	char	*path, **args;
-
-	args = list_new();
+	char	*path;
 
 	if (libexec_dir == NULL) {
 		path = xasprintf("%s/%slint2", PATH_LIBEXEC, target_prefix);
@@ -893,22 +850,21 @@ run_lint2(void)
 		path = concat2(libexec_dir, "/lint2");
 	}
 
+	list args = { NULL, 0, 0 };
 	list_add(&args, path);
-	list_add_all(&args, lint2.flags);
-	list_add_all(&args, lint2.inlibs);
-	list_add_all(&args, lint2.infiles);
+	list_add_all(&args, &lint2.flags);
+	list_add_all(&args, &lint2.inlibs);
+	list_add_all(&args, &lint2.infiles);
 
-	run_child(path, args, lint2.outlib, -1);
+	run_child(path, &args, lint2.outlib, -1);
 	free(path);
 	list_clear(&args);
-	free(args);
 }
 
 static void
-cat(char *const *srcs, const char *dest)
+cat(const list *srcs, const char *dest)
 {
-	int	ifd, ofd, i;
-	char	*src;
+	int	ifd, ofd;
 	ssize_t	rlen;
 	char	buf[0x4000];
 
@@ -917,7 +873,8 @@ cat(char *const *srcs, const char *dest)
 		terminate(-1);
 	}
 
-	for (i = 0; (src = srcs[i]) != NULL; i++) {
+	for (size_t i = 0; i < srcs->len; i++) {
+		const char *src = srcs->items[i];
 		if ((ifd = open(src, O_RDONLY)) == -1) {
 			warn("cannot open %s", src);
 			terminate(-1);

Reply via email to