hi.
I was playing around with Linux and tmpfs, I made a big bunch
of dirs. I really mean BIG. Names were "A" x 2000.
$ rm -rf A*
Segmentation fault
$ du -sh
Segmentation fault
$
I have x86 Linux 2.4.18-rc2, glibc-2.2.4-19.3, fileutils-4.1 & 4.1.7.
Here gdb debug stuff from v4.1.7:
Program received signal SIGSEGV, Segmentation fault.
0x08049e66 in remove_dir (fs=0xbf7cc260, need_save_cwd=0, x=0xbffc8d60,
cwd_dev_ino=0xbf7ccb60) at remove.c:656
656 char *dir_name = fs->filename;
(gdb) bt
#0 0x08049e66 in remove_dir (fs=0xbf7cc260, need_save_cwd=0, x=0xbffc8d60,
cwd_dev_ino=0xbf7ccb60) at remove.c:656
#1 0x0804a7e5 in rm (fs=0xbf7cc260, user_specified_name=0, x=0xbffc8d60,
cwd_dev_ino=0xbf7ccb60) at remove.c:906
#2 0x08049992 in remove_cwd_entries (x=0xbffc8d60, cwd_dev_ino=0xbf7ccb60)
at remove.c:536
#3 0x0804a14d in remove_dir (fs=0xbf7ccd00, need_save_cwd=0, x=0xbffc8d60,
cwd_dev_ino=0xbf7cd600) at remove.c:732
#4 0x0804a7e5 in rm (fs=0xbf7ccd00, user_specified_name=0, x=0xbffc8d60,
cwd_dev_ino=0xbf7cd600) at remove.c:906
...
(gdb) print *fs
$14 = {filename = 0x8053d43 'A' <repeats 200 times>..., have_filetype_mode = 1,
have_full_mode = 1, have_device = 1, mode = 16832, st_ino = 38654705664,
st_dev = 595832223039488000}
(gdb) disass $eip-32 $eip+32
Dump of assembler code from 0x8049e46 to 0x8049e86:
0x8049e46 <remove_file+630>: in (%dx),%eax
0x8049e47 <remove_file+631>: (bad)
0x8049e48 <remove_file+632>: decl 0x26b4(%ebp)
0x8049e4e <remove_file+638>: add %al,(%eax)
0x8049e50 <remove_dir>: push %ebp
0x8049e51 <remove_dir+1>: mov %esp,%ebp
0x8049e53 <remove_dir+3>: push %edi
0x8049e54 <remove_dir+4>: push %esi
0x8049e55 <remove_dir+5>: push %ebx
0x8049e56 <remove_dir+6>: xor %ebx,%ebx
0x8049e58 <remove_dir+8>: sub $0xfc,%esp
0x8049e5e <remove_dir+14>: mov 0x10(%ebp),%edx
0x8049e61 <remove_dir+17>: mov 0x8(%ebp),%eax
0x8049e64 <remove_dir+20>: mov (%eax),%eax
0x8049e66 <remove_dir+22>: mov %eax,0xffffff04(%ebp) <<<===
0x8049e6c <remove_dir+28>: mov 0x8(%edx),%edx
0x8049e6f <remove_dir+31>: test %edx,%edx
0x8049e71 <remove_dir+33>: je 0x804a5e0 <remove_dir+1936>
0x8049e77 <remove_dir+39>: mov 0x10(%ebp),%ecx
0x8049e7a <remove_dir+42>: mov (%ecx),%edi
0x8049e7c <remove_dir+44>: test %edi,%edi
0x8049e7e <remove_dir+46>: je 0x804a590 <remove_dir+1856>
0x8049e84 <remove_dir+52>: mov 0x10(%ebp),%esi
(gdb) print $ebp
$16 = (void *) 0xbf7cc0e8
(PAGE_OFFSET - $ebp) is about my stack size (8192 KiB) in resource limits.
Can rm/du/etc memory usage be optimized? It needs to keep names of all
the dirs it traverses in memory?
Hmh, if that's the case, maybe I'll just create a specially crafted rm
which can remove those evil dirs (or just umount this time).
I don't know if find would work if I had more mem, now kernel says
kernel: Out of Memory: Killed process 28099 (find).
At least it didn't run out of stack.
"ls -R" fails in the beginning with "file name too long".
--
Safari - [EMAIL PROTECTED] - PGP key 0x427E7914 - http://iki.fi/safari/
The UNIX Guru's View of Sex: "unzip ; strip ; touch ; finger ; \
mount ; fsck ; more ; yes ; umount ; sleep"
#include <sys/stat.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#define EVILSIZE 2000
int main(void)
{
char dir_A[EVILSIZE];
memset(dir_A, 'A', EVILSIZE);
dir_A[EVILSIZE-1] = 0;
while(1) {
if(mkdir(dir_A, S_IRWXU) != 0) {
if(errno == EEXIST) {
if(chdir(dir_A) == 0) {
continue;
} else {
goto plonk;
}
}
fprintf(stderr, "mkdir: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if(chdir(dir_A) != 0) {
plonk:
fprintf(stderr, "chdir: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
}
return EXIT_SUCCESS;
}