mugwumpjism has asked for the wisdom of the Perl Monks concerning the following question:
The below .XS routine performs a readdir(), but returns the inode numbers of the directory entries at the same time (this information should always be available, and in some situations it might save you a fair few calls to stat(), such as in unify-dirs).
The code seems to work perfectly, but for one directory, I get a segfault every time. The segfault happens after the sub has returned, in Perl_sv_setsv (eval.c:41). Can anyone see anything glaringly wrong with this Xsub?
/* <=-*- C -*-=> */ #include "EXTERN.h" #include "perl.h" #include "XSUB.h" #include <sys/types.h> #include <dirent.h> #include <stdio.h> MODULE = ReadDir PACKAGE = ReadDir void readdir_inode(dirname) char* dirname INIT: struct dirent *ent; DIR* dir; SV* record[2]; AV *entry, *ret_val; PPCODE: dir = opendir(dirname); if (dir) { while ((ent=readdir(dir))) { record[0] = newSVpv(ent->d_name, 0); record[1] = newSViv((IV)ent->d_ino); PUSHs(sv_2mortal(newRV_inc((SV*)av_make(2, record)))); } closedir(dir); }
Here is a transcript of the debugger session:
vshost:~# gdb /usr/bin/perl GNU gdb 5.0rh-5 Red Hat Linux 7.1 Copyright 2001 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and y +ou are welcome to change it and/or distribute copies of it under certain cond +itions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for det +ails. This GDB was configured as "i386-redhat-linux"... (no debugging symbols found)... (gdb) run -d ./unify-dirs -dil /vservers/*/usr/share/man/man1 Starting program: /usr/bin/perl -d ./unify-dirs -dil /vservers/*/usr/s +hare/man/man1 Default die handler restored. Loading DB routines from perl5db.pl version 1.07 Editor support available. Enter h or `h h' for help, or `man perldebug' for more help. main::(./unify-dirs:187): my ($action, @dirs, $immutable, $linka +ge, $mode); DB<1> Program received signal SIGINT, Interrupt. 0x40133f44 in __libc_read () from /lib/i686/libc.so.6 (gdb) b XS_ReadDir_readdir_inode Breakpoint 1 at 0x401e7b48: file ReadDir.c, line 22. (gdb) c Continuing. c unify-dirs: Unifying: /vservers/babelfish/usr/share/man/man1 /vservers +/compileit/usr/share/man/man1 /vservers/dev/usr/share/man/man1 /vserv +ers/easystrike/usr/share/man/man1 /vservers/master-/usr/share/man/man +1 /vservers/master/usr/share/man/man1 /vservers/vs1/usr/share/man/man +1 /vservers/vs2/usr/share/man/man1 /vservers/webrt/usr/share/man/man1 unify-dirs: Processing /vservers/babelfish/usr/share/man/man1... Breakpoint 1, XS_ReadDir_readdir_inode (cv=0x82f7114) at ReadDir.c:22 22 dXSARGS; (gdb) c Continuing. unify-dirs: Readdir OK unify-dirs: Processing /vservers/compileit/usr/share/man/man1... Breakpoint 1, XS_ReadDir_readdir_inode (cv=0x82f7114) at ReadDir.c:22 22 dXSARGS; (gdb) n 23 if (items != 1) (gdb) 27 char* dirname = (char *)SvPV(ST(0),PL_na); (gdb) 25 SP -= items; (gdb) 27 char* dirname = (char *)SvPV(ST(0),PL_na); (gdb) 21 dir = opendir(dirname); (gdb) 22 if (dir) { (gdb) 23 while ((ent=readdir(dir))) { (gdb) 24 record[0] = newSVpv(ent->d_name, 0); (gdb) p ent->d_name $1 = ".\000\000\000\000\203%\020\000\030\000\000\000\020\000\004..\000 +\000\000\002x\t\0000\000\000\000 \000\bbuiltins.1.gz\000\000\000\000\ +000\000\000\000\003x\t\000@\000\000\000\030\000\nsh.1.gz\000\000\000\ +000\000\000ÿw\t\000T\000\000\000\030\000\brbash.1.gz\000\000\000\000x +\t\000h\000\000\000\030\000\bbash.1.gz\000\000\000\000\001x\t\000|\00 +0\000\000\030\000\bbashbug.1.gz\000\213u\t\000\230\000\000\000 \000\b +sensible-editor.1.gz\000\214u\t\000¬\000\000\000\030\000\bmktemp.1".. +. (gdb) n 26 PUSHs(sv_2mortal(newRV_inc((SV*)av_make(2, record)))); (gdb) n 24 record[0] = newSVpv(ent->d_name, 0); (gdb) n 25 record[1] = newSViv((IV)ent->d_ino); (gdb) 26 PUSHs(sv_2mortal(newRV_inc((SV*)av_make(2, record)))); (gdb) p $ent->d_ino Attempt to extract a component of a value that is not a structure poin +ter. (gdb) p ent->d_ino $2 = 1058181 (gdb) fin Run till exit from #0 XS_ReadDir_readdir_inode (cv=0x82f7114) at Read +Dir.xs:26 0x0809dd2c in Perl_pp_entersub () at eval.c:41 41 eval.c: No such file or directory. in eval.c (gdb) fin Run till exit from #0 0x0809dd2c in Perl_pp_entersub () at eval.c:41 0x08098658 in Perl_runops_standard () at eval.c:41 41 in eval.c (gdb) fin Run till exit from #0 0x08098658 in Perl_runops_standard () at eval.c +:41 Program received signal SIGSEGV, Segmentation fault. 0x080a1ea9 in Perl_sv_setsv () at eval.c:41 41 in eval.c (gdb) bt #0 0x080a1ea9 in Perl_sv_setsv () at eval.c:41 #1 0x080a5509 in Perl_sv_mortalcopy () at eval.c:41 #2 0x0809a3a6 in Perl_pp_aassign () at eval.c:41 #3 0x08098658 in Perl_runops_standard () at eval.c:41 #4 0x0805bf91 in perl_run () at eval.c:41 #5 0x0805bd2b in perl_run () at eval.c:41 #6 0x08059a21 in main () at eval.c:41 #7 0x40076177 in __libc_start_main (main=0x80599b0 <main>, argc=13, ubp_av=0xbffff9f4, init=0x8058b80 <_init>, fini=0x80df83c <_fini>, + rtld_fini=0x4000e184 <_dl_fini>, stack_end=0xbffff9ec) at ../sysdeps/generic/libc-start.c:129 (gdb)
|
|---|
| Replies are listed 'Best First'. | |
|---|---|
|
Re: .XS segfault
by derby (Abbot) on Mar 08, 2002 at 14:18 UTC | |
by mugwumpjism (Hermit) on Mar 08, 2002 at 16:09 UTC | |
by derby (Abbot) on Mar 08, 2002 at 16:46 UTC |