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;
}

Reply via email to