commit 65fae61bea713e004b7698cb424fa2a24847b40d
parent 6d4166f0d6b67bbaecb57cdf821d28f4356ae67f
Author: sin <sin@2f30.org>
Date: Thu, 7 Jan 2016 10:26:44 +0000
noice: No need to perform so many memory allocations
The code was quite fragile. As a first pass, use buffers of size
PATH_MAX and LINE_MAX accordingly until we simplify the overall logic.
Diffstat:
M | noice.c | | | 140 | +++++++++++++++++++++++++++++++------------------------------------------------ |
1 file changed, 55 insertions(+), 85 deletions(-)
diff --git a/noice.c b/noice.c
@@ -74,7 +74,7 @@ struct key {
#include "config.h"
struct entry {
- char *name;
+ char name[PATH_MAX];
mode_t mode;
time_t t;
};
@@ -82,8 +82,8 @@ struct entry {
/* Global context */
struct entry *dents;
int n, cur;
-char *path, *oldpath;
-char *fltr;
+char path[PATH_MAX], oldpath[PATH_MAX];
+char fltr[LINE_MAX];
int idle;
/*
@@ -106,7 +106,7 @@ int idle;
void printmsg(char *);
void printwarn(void);
void printerr(int, char *);
-char *mkpath(char *, char *);
+char *mkpath(char *, char *, char *, size_t);
#undef dprintf
int
@@ -155,20 +155,20 @@ xstrdup(const char *s)
return p;
}
+/* Some implementations of dirname(3) may modify `path' and some
+ * return a pointer inside `path'. */
char *
xdirname(const char *path)
{
+ static char out[PATH_MAX];
char tmp[PATH_MAX], *p;
- /* Some implementations of dirname(3) may modify `path' and some
- * return a pointer inside `path' and we cannot free(3) the
- * original string if we lose track of it. */
strlcpy(tmp, path, sizeof(tmp));
p = dirname(tmp);
if (p == NULL)
printerr(1, "dirname");
- /* Make sure this is a malloc(3)-ed string */
- return xstrdup(p);
+ strlcpy(out, p, sizeof(out));
+ return out;
}
void
@@ -226,15 +226,17 @@ openwith(char *file)
int
setfilter(regex_t *regex, char *filter)
{
- char *errbuf;
+ char errbuf[LINE_MAX];
+ size_t len;
int r;
r = regcomp(regex, filter, REG_NOSUB | REG_EXTENDED | REG_ICASE);
if (r != 0) {
- errbuf = xmalloc(COLS);
- regerror(r, regex, errbuf, COLS);
+ len = COLS;
+ if (len > sizeof(errbuf))
+ len = sizeof(errbuf);
+ regerror(r, regex, errbuf, len);
printmsg(errbuf);
- free(errbuf);
}
return r;
@@ -461,10 +463,10 @@ int
dentfill(char *path, struct entry **dents,
int (*filter)(regex_t *, char *), regex_t *re)
{
+ char newpath[PATH_MAX];
DIR *dirp;
struct dirent *dp;
struct stat sb;
- char *newpath;
int r, n = 0;
dirp = opendir(path);
@@ -479,13 +481,12 @@ dentfill(char *path, struct entry **dents,
if (filter(re, dp->d_name) == 0)
continue;
*dents = xrealloc(*dents, (n + 1) * sizeof(**dents));
- (*dents)[n].name = xstrdup(dp->d_name);
+ strlcpy((*dents)[n].name, dp->d_name, sizeof((*dents)[n].name));
/* Get mode flags */
- newpath = mkpath(path, dp->d_name);
+ mkpath(path, dp->d_name, newpath, sizeof(newpath));
r = lstat(newpath, &sb);
if (r == -1)
printerr(1, "lstat");
- free(newpath);
(*dents)[n].mode = sb.st_mode;
(*dents)[n].t = sb.st_mtime;
n++;
@@ -500,58 +501,47 @@ dentfill(char *path, struct entry **dents,
}
void
-dentfree(struct entry *dents, int n)
+dentfree(struct entry *dents)
{
- int i;
-
- for (i = 0; i < n; i++)
- free(dents[i].name);
free(dents);
}
char *
-mkpath(char *dir, char *name)
+mkpath(char *dir, char *name, char *out, size_t n)
{
- char path[PATH_MAX];
-
/* Handle absolute path */
if (name[0] == '/') {
- strlcpy(path, name, sizeof(path));
+ strlcpy(out, name, n);
} else {
/* Handle root case */
if (strcmp(dir, "/") == 0) {
- strlcpy(path, "/", sizeof(path));
- strlcat(path, name, sizeof(path));
+ strlcpy(out, "/", n);
+ strlcat(out, name, n);
} else {
- strlcpy(path, dir, sizeof(path));
- strlcat(path, "/", sizeof(path));
- strlcat(path, name, sizeof(path));
+ strlcpy(out, dir, n);
+ strlcat(out, "/", n);
+ strlcat(out, name, n);
}
}
- return xstrdup(path);
+ return out;
}
/* Return the position of the matching entry or 0 otherwise */
int
dentfind(struct entry *dents, int n, char *cwd, char *path)
{
+ char tmp[PATH_MAX];
int i;
- char *tmp;
if (path == NULL)
return 0;
-
for (i = 0; i < n; i++) {
- tmp = mkpath(cwd, dents[i].name);
+ mkpath(cwd, dents[i].name, tmp, sizeof(tmp));
DPRINTF_S(path);
DPRINTF_S(tmp);
- if (strcmp(tmp, path) == 0) {
- free(tmp);
+ if (strcmp(tmp, path) == 0)
return i;
- }
- free(tmp);
}
-
return 0;
}
@@ -570,7 +560,7 @@ populate(void)
if (r != 0)
return -1;
- dentfree(dents, n);
+ dentfree(dents);
n = 0;
dents = NULL;
@@ -581,9 +571,6 @@ populate(void)
/* Find cur from history */
cur = dentfind(dents, n, path, oldpath);
- free(oldpath);
- oldpath = NULL;
-
return 0;
}
@@ -638,18 +625,16 @@ redraw(void)
void
browse(const char *ipath, const char *ifilter)
{
- int r, fd;
- regex_t re;
- char *newpath;
- struct stat sb;
+ char newpath[PATH_MAX];
char *name, *bin, *dir, *tmp, *run, *env;
+ struct stat sb;
+ regex_t re;
+ int r, fd;
int nowtyping = 0;
- oldpath = NULL;
- path = xstrdup(ipath);
- fltr = xstrdup(ifilter);
+ strlcpy(path, ipath, sizeof(path));
+ strlcpy(fltr, ifilter, sizeof(fltr));
begin:
- /* Path and filter should be malloc(3)-ed strings at all times */
r = populate();
if (r == -1) {
if (!nowtyping) {
@@ -667,9 +652,7 @@ begin:
nochange:
switch (nextsel(&run, &env)) {
case SEL_QUIT:
- free(path);
- free(fltr);
- dentfree(dents, n);
+ dentfree(dents);
return;
case SEL_BACK:
/* There is no going back */
@@ -679,16 +662,14 @@ nochange:
goto nochange;
dir = xdirname(path);
if (canopendir(dir) == 0) {
- free(dir);
printwarn();
goto nochange;
}
/* Save history */
- oldpath = path;
- path = dir;
+ strlcpy(oldpath, path, sizeof(path));
+ strlcpy(path, dir, sizeof(path));
/* Reset filter */
- free(fltr);
- fltr = xstrdup(ifilter);
+ strlcpy(fltr, ifilter, sizeof(fltr));
goto begin;
case SEL_GOIN:
/* Cannot descend in empty directories */
@@ -696,21 +677,19 @@ nochange:
goto nochange;
name = dents[cur].name;
- newpath = mkpath(path, name);
+ mkpath(path, name, newpath, sizeof(newpath));
DPRINTF_S(newpath);
/* Get path info */
fd = open(newpath, O_RDONLY | O_NONBLOCK);
if (fd == -1) {
printwarn();
- free(newpath);
goto nochange;
}
r = fstat(fd, &sb);
if (r == -1) {
printwarn();
close(fd);
- free(newpath);
goto nochange;
}
close(fd);
@@ -720,26 +699,21 @@ nochange:
case S_IFDIR:
if (canopendir(newpath) == 0) {
printwarn();
- free(newpath);
goto nochange;
}
- free(path);
- path = newpath;
+ strlcpy(path, newpath, sizeof(path));
/* Reset filter */
- free(fltr);
- fltr = xstrdup(ifilter);
+ strlcpy(fltr, ifilter, sizeof(fltr));
goto begin;
case S_IFREG:
bin = openwith(newpath);
if (bin == NULL) {
printmsg("No association");
- free(newpath);
goto nochange;
}
exitcurses();
spawn(bin, newpath, NULL);
initcurses();
- free(newpath);
continue;
default:
printmsg("Unsupported file");
@@ -757,12 +731,11 @@ nochange:
free(tmp);
goto nochange;
}
- free(fltr);
- fltr = tmp;
+ strlcpy(fltr, tmp, sizeof(fltr));
DPRINTF_S(fltr);
/* Save current */
if (n > 0)
- oldpath = mkpath(path, dents[cur].name);
+ mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
goto begin;
case SEL_TYPE:
nowtyping = 1;
@@ -788,14 +761,13 @@ moretyping:
}
}
/* Copy or reset filter */
- free(fltr);
if (tmp != NULL)
- fltr = xstrdup(tmp);
+ strlcpy(fltr, tmp, sizeof(fltr));
else
- fltr = xstrdup(ifilter);
+ strlcpy(fltr, ifilter, sizeof(fltr));
/* Save current */
if (n > 0)
- oldpath = mkpath(path, dents[cur].name);
+ mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
if (!nowtyping)
free(tmp);
goto begin;
@@ -829,29 +801,27 @@ moretyping:
clearprompt();
goto nochange;
}
- newpath = mkpath(path, tmp);
+ mkpath(path, tmp, newpath, sizeof(newpath));
free(tmp);
if (canopendir(newpath) == 0) {
- free(newpath);
printwarn();
goto nochange;
}
- free(path);
- path = newpath;
- free(fltr);
- fltr = xstrdup(ifilter); /* Reset filter */
+ strlcpy(path, newpath, sizeof(path));
+ /* Reset filter */
+ strlcpy(fltr, ifilter, sizeof(fltr))
DPRINTF_S(path);
goto begin;
case SEL_MTIME:
mtimeorder = !mtimeorder;
/* Save current */
if (n > 0)
- oldpath = mkpath(path, dents[cur].name);
+ mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
goto begin;
case SEL_REDRAW:
/* Save current */
if (n > 0)
- oldpath = mkpath(path, dents[cur].name);
+ mkpath(path, dents[cur].name, oldpath, sizeof(oldpath));
goto begin;
case SEL_RUN:
run = xgetenv(env, run);