Handle malloc failure by pausing any activity
This is a best-effort approach to save ncdu state when memory is low. There's likely allocation in libraries that isn't being checked (ncurses, printf). Fixes #132 (it actually doesn't, that needs a 64bit static binary too, but I'll get to that)
Этот коммит содержится в:
родитель
cd38a62aa8
Коммит
bb7b4196f2
@ -44,7 +44,7 @@ static int lasterrl; /* ^ of lasterr */
|
||||
static void curpath_resize(int s) {
|
||||
if(curpathl < s) {
|
||||
curpathl = s < 128 ? 128 : s < curpathl*2 ? curpathl*2 : s;
|
||||
dir_curpath = realloc(dir_curpath, curpathl);
|
||||
dir_curpath = xrealloc(dir_curpath, curpathl);
|
||||
}
|
||||
}
|
||||
|
||||
@ -85,7 +85,7 @@ void dir_setlasterr(const char *path) {
|
||||
int req = strlen(path)+1;
|
||||
if(lasterrl < req) {
|
||||
lasterrl = req;
|
||||
lasterr = realloc(lasterr, lasterrl);
|
||||
lasterr = xrealloc(lasterr, lasterrl);
|
||||
}
|
||||
strcpy(lasterr, path);
|
||||
}
|
||||
@ -99,7 +99,7 @@ void dir_seterr(const char *fmt, ...) {
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
dir_fatalerr = malloc(1024); /* Should be enough for everything... */
|
||||
dir_fatalerr = xmalloc(1024); /* Should be enough for everything... */
|
||||
vsnprintf(dir_fatalerr, 1023, fmt, va);
|
||||
dir_fatalerr[1023] = 0;
|
||||
va_end(va);
|
||||
|
@ -596,12 +596,12 @@ int dir_import_init(const char *fn) {
|
||||
else if((stream = fopen(fn, "r")) == NULL)
|
||||
return 1;
|
||||
|
||||
ctx = malloc(sizeof(struct ctx));
|
||||
ctx = xmalloc(sizeof(struct ctx));
|
||||
ctx->stream = stream;
|
||||
ctx->line = 1;
|
||||
ctx->byte = ctx->eof = ctx->items = 0;
|
||||
ctx->buf = ctx->lastfill = ctx->readbuf;
|
||||
ctx->buf_dir = malloc(dir_memsize(""));
|
||||
ctx->buf_dir = xmalloc(dir_memsize(""));
|
||||
ctx->readbuf[0] = 0;
|
||||
|
||||
dir_curpath_set(fn);
|
||||
|
@ -123,7 +123,7 @@ static int item(struct dir *dir, const char *name, struct dir_ext *ext) {
|
||||
|
||||
if(!extended_info)
|
||||
dir->flags &= ~FF_EXT;
|
||||
item = malloc(dir->flags & FF_EXT ? dir_ext_memsize(name) : dir_memsize(name));
|
||||
item = xmalloc(dir->flags & FF_EXT ? dir_ext_memsize(name) : dir_memsize(name));
|
||||
memcpy(item, dir, offsetof(struct dir, name));
|
||||
strcpy(item->name, name);
|
||||
if(dir->flags & FF_EXT)
|
||||
|
@ -100,7 +100,7 @@ static char *dir_read(int *err) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
buf = malloc(buflen);
|
||||
buf = xmalloc(buflen);
|
||||
errno = 0;
|
||||
|
||||
while((item = readdir(dir)) != NULL) {
|
||||
@ -109,7 +109,7 @@ static char *dir_read(int *err) {
|
||||
int req = off+3+strlen(item->d_name);
|
||||
if(req > buflen) {
|
||||
buflen = req < buflen*2 ? buflen*2 : req;
|
||||
buf = realloc(buf, buflen);
|
||||
buf = xrealloc(buf, buflen);
|
||||
}
|
||||
strcpy(buf+off, item->d_name);
|
||||
off += strlen(item->d_name)+1;
|
||||
@ -313,6 +313,6 @@ void dir_scan_init(const char *path) {
|
||||
dir_seterr(NULL);
|
||||
dir_process = process;
|
||||
if (!buf_dir)
|
||||
buf_dir = malloc(dir_memsize(""));
|
||||
buf_dir = xmalloc(dir_memsize(""));
|
||||
pstate = ST_CALC;
|
||||
}
|
||||
|
@ -217,7 +217,7 @@ void dirlist_open(struct dir *d) {
|
||||
/* set the reference to the parent dir */
|
||||
if(d->parent) {
|
||||
if(!parent_alloc)
|
||||
parent_alloc = calloc(1, dir_memsize(".."));
|
||||
parent_alloc = xcalloc(1, dir_memsize(".."));
|
||||
dirlist_parent = parent_alloc;
|
||||
strcpy(dirlist_parent->name, "..");
|
||||
dirlist_parent->next = head;
|
||||
|
@ -23,7 +23,7 @@
|
||||
|
||||
*/
|
||||
|
||||
#include "exclude.h"
|
||||
#include "global.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@ -45,8 +45,8 @@ void exclude_add(char *pat) {
|
||||
while(*n != NULL)
|
||||
n = &((*n)->next);
|
||||
|
||||
*n = (struct exclude *) calloc(1, sizeof(struct exclude));
|
||||
(*n)->pattern = (char *) malloc(strlen(pat)+1);
|
||||
*n = (struct exclude *) xcalloc(1, sizeof(struct exclude));
|
||||
(*n)->pattern = (char *) xmalloc(strlen(pat)+1);
|
||||
strcpy((*n)->pattern, pat);
|
||||
}
|
||||
|
||||
@ -125,7 +125,7 @@ int has_cachedir_tag(const char *name) {
|
||||
/* We don't need to copy the content of `path`, so it's more efficient to
|
||||
* use `free` + `malloc`. */
|
||||
free(path);
|
||||
path = malloc(path_l);
|
||||
path = xmalloc(path_l);
|
||||
}
|
||||
snprintf(path, path_l, "%s/%s", name, CACHEDIR_TAG_FILENAME);
|
||||
f = fopen(path, "rb");
|
||||
|
@ -109,6 +109,9 @@ extern int follow_symlinks;
|
||||
/* handle input from keyboard and update display */
|
||||
int input_handle(int);
|
||||
|
||||
/* de-initialize ncurses */
|
||||
void close_nc();
|
||||
|
||||
|
||||
/* import all other global functions and variables */
|
||||
#include "browser.h"
|
||||
|
15
src/main.c
15
src/main.c
@ -280,6 +280,15 @@ static void init_nc() {
|
||||
}
|
||||
|
||||
|
||||
void close_nc() {
|
||||
if(ncurses_init) {
|
||||
erase();
|
||||
refresh();
|
||||
endwin();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* main program */
|
||||
int main(int argc, char **argv) {
|
||||
read_locale();
|
||||
@ -309,11 +318,7 @@ int main(int argc, char **argv) {
|
||||
break;
|
||||
}
|
||||
|
||||
if(ncurses_init) {
|
||||
erase();
|
||||
refresh();
|
||||
endwin();
|
||||
}
|
||||
close_nc();
|
||||
exclude_clear();
|
||||
|
||||
return 0;
|
||||
|
24
src/path.c
24
src/path.c
@ -23,7 +23,7 @@
|
||||
|
||||
*/
|
||||
|
||||
#include "path.h"
|
||||
#include "global.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
@ -64,8 +64,8 @@ static int path_split(char *cur, char ***res) {
|
||||
}
|
||||
|
||||
/* create array of the components */
|
||||
old = malloc((j+1)*sizeof(char *));
|
||||
*res = malloc((j+1)*sizeof(char *));
|
||||
old = xmalloc((j+1)*sizeof(char *));
|
||||
*res = xmalloc((j+1)*sizeof(char *));
|
||||
for(i=j=0; i<n; i++)
|
||||
if(i == 0 || (cur[i-1] == 0 && cur[i] != 0))
|
||||
old[j++] = cur+i;
|
||||
@ -98,11 +98,11 @@ static char *path_absolute(const char *path) {
|
||||
/* not an absolute path? prepend cwd */
|
||||
if(path[0] != '/') {
|
||||
n = RPATH_CNKSZ;
|
||||
ret = malloc(n);
|
||||
ret = xmalloc(n);
|
||||
errno = 0;
|
||||
while(!getcwd(ret, n) && errno == ERANGE) {
|
||||
n += RPATH_CNKSZ;
|
||||
ret = realloc(ret, n);
|
||||
ret = xrealloc(ret, n);
|
||||
errno = 0;
|
||||
}
|
||||
if(errno) {
|
||||
@ -112,12 +112,12 @@ static char *path_absolute(const char *path) {
|
||||
|
||||
i = strlen(path) + strlen(ret) + 2;
|
||||
if(i > n)
|
||||
ret = realloc(ret, i);
|
||||
ret = xrealloc(ret, i);
|
||||
strcat(ret, "/");
|
||||
strcat(ret, path);
|
||||
/* otherwise, just make a copy */
|
||||
} else {
|
||||
ret = malloc(strlen(path)+1);
|
||||
ret = xmalloc(strlen(path)+1);
|
||||
strcpy(ret, path);
|
||||
}
|
||||
return ret;
|
||||
@ -133,7 +133,7 @@ static char *path_real_rec(char *cur, int *links) {
|
||||
char **arr, *tmp, *lnk = NULL, *ret = NULL;
|
||||
|
||||
tmpl = strlen(cur)+1;
|
||||
tmp = malloc(tmpl);
|
||||
tmp = xmalloc(tmpl);
|
||||
|
||||
/* split path */
|
||||
i = path_split(cur, &arr);
|
||||
@ -142,7 +142,7 @@ static char *path_real_rec(char *cur, int *links) {
|
||||
strcpy(tmp, "/");
|
||||
if(i > 0) {
|
||||
lnkl = RPATH_CNKSZ;
|
||||
lnk = malloc(lnkl);
|
||||
lnk = xmalloc(lnkl);
|
||||
if(chdir("/") < 0)
|
||||
goto path_real_done;
|
||||
}
|
||||
@ -153,7 +153,7 @@ static char *path_real_rec(char *cur, int *links) {
|
||||
/* check for symlink */
|
||||
while((n = readlink(arr[i], lnk, lnkl)) == lnkl || (n < 0 && errno == ERANGE)) {
|
||||
lnkl += RPATH_CNKSZ;
|
||||
lnk = realloc(lnk, lnkl);
|
||||
lnk = xrealloc(lnk, lnkl);
|
||||
}
|
||||
if(n < 0 && errno != EINVAL)
|
||||
goto path_real_done;
|
||||
@ -168,7 +168,7 @@ static char *path_real_rec(char *cur, int *links) {
|
||||
n += strlen(tmp);
|
||||
if(tmpl < n) {
|
||||
tmpl = n;
|
||||
tmp = realloc(tmp, tmpl);
|
||||
tmp = xrealloc(tmp, tmpl);
|
||||
}
|
||||
if(lnk[0] != '/')
|
||||
strcat(tmp, lnk);
|
||||
@ -179,7 +179,7 @@ static char *path_real_rec(char *cur, int *links) {
|
||||
n += strlen(arr[i])+1;
|
||||
if(tmpl < n) {
|
||||
tmpl = n;
|
||||
tmp = realloc(tmp, tmpl);
|
||||
tmp = xrealloc(tmp, tmpl);
|
||||
}
|
||||
strcat(tmp, "/");
|
||||
strcat(tmp, arr[i]);
|
||||
|
@ -30,7 +30,6 @@
|
||||
- path_real uses chdir(), so it's not thread safe
|
||||
- Process requires +x access for all directory components
|
||||
- Potentionally slow
|
||||
- Doesn't check return value of malloc() and realloc()
|
||||
- path_real doesn't check for the existance of the last component
|
||||
- cwd is unreliable after path_real
|
||||
*/
|
||||
|
25
src/util.c
25
src/util.c
@ -29,6 +29,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <ncurses.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
#ifdef HAVE_LOCALE_H
|
||||
#include <locale.h>
|
||||
#endif
|
||||
@ -371,12 +372,12 @@ char *getpath(struct dir *cur) {
|
||||
|
||||
if(datl == 0) {
|
||||
datl = i;
|
||||
dat = malloc(i);
|
||||
dat = xmalloc(i);
|
||||
} else if(datl < i) {
|
||||
datl = i;
|
||||
dat = realloc(dat, i);
|
||||
dat = xrealloc(dat, i);
|
||||
}
|
||||
list = malloc(c*sizeof(struct dir *));
|
||||
list = xmalloc(c*sizeof(struct dir *));
|
||||
|
||||
c = 0;
|
||||
for(d=cur; d!=NULL; d=d->parent)
|
||||
@ -413,3 +414,21 @@ void addparentstats(struct dir *d, int64_t size, int64_t asize, uint64_t mtime,
|
||||
d = d->parent;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* Apparently we can just resume drawing after endwin() and ncurses will pick
|
||||
* up where it left. Probably not very portable... */
|
||||
#define oom_msg "\nOut of memory, press enter to try again or Ctrl-C to give up.\n"
|
||||
#define wrap_oom(f) \
|
||||
void *ptr;\
|
||||
char buf[128];\
|
||||
while((ptr = f) == NULL) {\
|
||||
close_nc();\
|
||||
write(2, oom_msg, sizeof(oom_msg));\
|
||||
read(0, buf, sizeof(buf));\
|
||||
}\
|
||||
return ptr;
|
||||
|
||||
void *xmalloc(size_t size) { wrap_oom(malloc(size)) }
|
||||
void *xcalloc(size_t n, size_t size) { wrap_oom(calloc(n, size)) }
|
||||
void *xrealloc(void *mem, size_t size) { wrap_oom(realloc(mem, size)) }
|
||||
|
@ -170,13 +170,13 @@ void addparentstats(struct dir *, int64_t, int64_t, uint64_t, int);
|
||||
#define nstack_init(_s) do {\
|
||||
(_s)->size = 10;\
|
||||
(_s)->top = 0;\
|
||||
(_s)->list = malloc(10*sizeof(*(_s)->list));\
|
||||
(_s)->list = xmalloc(10*sizeof(*(_s)->list));\
|
||||
} while(0)
|
||||
|
||||
#define nstack_push(_s, _v) do {\
|
||||
if((_s)->size <= (_s)->top) {\
|
||||
(_s)->size *= 2;\
|
||||
(_s)->list = realloc((_s)->list, (_s)->size*sizeof(*(_s)->list));\
|
||||
(_s)->list = xrealloc((_s)->list, (_s)->size*sizeof(*(_s)->list));\
|
||||
}\
|
||||
(_s)->list[(_s)->top++] = _v;\
|
||||
} while(0)
|
||||
@ -186,5 +186,10 @@ void addparentstats(struct dir *, int64_t, int64_t, uint64_t, int);
|
||||
#define nstack_free(_s) free((_s)->list)
|
||||
|
||||
|
||||
/* Malloc wrappers that exit on OOM */
|
||||
void *xmalloc();
|
||||
void *xcalloc(size_t, size_t);
|
||||
void *xrealloc(void *, size_t);
|
||||
|
||||
#endif
|
||||
|
||||
|
Загрузка…
Ссылка в новой задаче
Block a user