0

私のアプリは特定のディレクトリを再帰的にスキャンし、それぞれの一意のパスをデータベースに保存します。ある時点で、segfault が発生し、glibc が起動します。

*** glibc detected *** ./test: double free or corruption (!prev): 0x08cd1a20 *** 

gdb はそれを確認します。

以下の関数を呼び出すと、問題が発生します。

int
populatePathDB(sqlite3* db, char *absolutePath)
{
 char *sql;
 sqlite3_stmt *stmt ;
 int ret;

 sql = "INSERT INTO paths (path) VALUES (?)";

 ret = sqlite3_prepare_v2(db,sql,-1,&stmt,NULL);
 if ( ret != SQLITE_OK)
  DB_ERR(db, sqlite3_errmsg(db));

 ret = sqlite3_bind_text(stmt, 1, absolutePath, -1, SQLITE_STATIC);
 if ( ret != SQLITE_OK)
  DB_ERR(db, sqlite3_errmsg(db));

 sqlite3_step(stmt);
 if ( ret != SQLITE_OK)
  DB_ERR(db, sqlite3_errmsg(db));

/* sqlite3_clear_bindings(stmt);
 if ( ret != SQLITE_OK)
  DB_ERR(db, sqlite3_errmsg(db));

 sqlite3_reset(stmt);
 if ( ret != SQLITE_OK)
  DB_ERR(db, sqlite3_errmsg(db)); */

 ret = sqlite3_finalize( stmt );
 if ( ret != SQLITE_OK)
  DB_ERR(db, sqlite3_errmsg(db));

 return SQLITE_OK;
}

変数absolutePath(呼び出し元によって割り当てられた)が2回削除されたと思います。SQLITE_TRANSIENT を使用しても、同じ障害が発生しました。

何か案は?

再帰スキャン機能の追加:

int walkDir( char *dir, unsigned int recursive)
{
 DIR* dirstream;
 struct stat statbuf;
 struct dirent *entry = NULL;
 int exists, fd;
 size_t dlen, entlen, nlen;
 size_t buflen = 0;
 char *baseName = NULL;

extern sqlite3 *magicDB_g;
extern sqlite3 *pathDB_g;

 assert (dir !=NULL);

 if ( ( dirstream = opendir(dir) ) == NULL ) {
  ERR_MSG("opendir");
  return (EXIT_FAILURE);
 }

dlen = strlen(dir);
buflen = MEMCHUNK;
if (dlen >= buflen)
  buflen = roundToNextPowerOf2(dlen);

baseName = xmalloc(buflen);

while ( ( entry = readdir(dirstream) ) ) {
    if(!strcmp(".",entry->d_name) ||
        ! strcmp("..",entry->d_name))
           continue;
  if (entry->d_name[0] == '.')
        continue;

  nlen = dlen + (entlen = strlen(entry->d_name));
  if (unlikely(nlen + 2 > buflen) )
        xrealloc(baseName, buflen << 1);

  if (dlen == 1 && *dir == '/' )
     sprintf(baseName, "%s%s" , dir, entry->d_name);
  else
     sprintf(baseName, "%s/%s" , dir, entry->d_name);
     /*snprintf (baseName, need + 2,"%s/%s", baseName, entry->d_name);*/

  exists = lstat(baseName, &statbuf);
  if (exists < 0)
        continue;

  if ( S_ISREG(statbuf.st_mode) && statbuf.st_size != 0 )
  {
     if ((fd = open(baseName, O_RDONLY)) == -1) {
           ERR_MSG("open");
           continue;
        }

    //fileSignature_v1(fd,NBYTES,magicDB_g);

     if ( close(fd) == -1)
        ERR_MSG("close");
  }

  if ( S_ISDIR(statbuf.st_mode) )
  {
     /* Create a absolute path database with unique entries */
     populatePathDB(pathDB_g, baseName); <-- No segfault if not called.
     if (recursive) {
    printf("basename: %s\n",baseName);
        walkDir(baseName,recursive);
     }
   }
}

 free(baseName); <-- Seems to be deleted twice when back from populatePathDB()

 if (closedir(dirstream) == -1)
    ERR_MSG("closedir");

 return (EXIT_SUCCESS);
}

エラーステートメントは次のとおりです。

Program received signal SIGSEGV, Segmentation fault.
_int_malloc (av=0x379440, bytes=34) at malloc.c:3598
3598    malloc.c: Aucun fichier ou dossier de ce type.
(gdb) bt
#0  _int_malloc (av=0x379440, bytes=34) at malloc.c:3598
#1  0x0024fd3c in __GI___libc_malloc (bytes=34) at malloc.c:2924
#2  0x0011541f in local_strdup (s=0xb7fe2a8c "/lib/i386-linux-gnu/libgcc_s.so.1") at dl-load.c:162
#3  0x001185d4 in _dl_map_object (loader=<optimized out>, name=<optimized out>, type=2, trace_mode=0, mode=-1879048191, nsid=0) at dl-load.c:2473
#4  0x00122d5d in dl_open_worker (a=0xbfffe690) at dl-open.c:225
#5  0x0011ecbf in _dl_catch_error (objname=0xbfffe6b4, errstring=0xbfffe6b8, mallocedp=0xbfffe6bf, operate=0x122c30 <dl_open_worker>, args=0xbfffe690)
    at dl-error.c:178
#6  0x001227e4 in _dl_open (file=0x334345 "libgcc_s.so.1", mode=-2147483647, caller_dlopen=0x2d7e38, nsid=-2, argc=2, argv=0xbffff314, env=0x8051040)
    at dl-open.c:639
#7  0x002fbd41 in do_dlopen (ptr=0xbfffe840) at dl-libc.c:89
#8  0x0011ecbf in _dl_catch_error (objname=0xbfffe814, errstring=0xbfffe818, mallocedp=0xbfffe81f, operate=0x2fbce0 <do_dlopen>, args=0xbfffe840)
    at dl-error.c:178
#9  0x002fbe37 in dlerror_run (operate=<optimized out>, args=<optimized out>) at dl-libc.c:48
#10 0x002fbec7 in __GI___libc_dlopen_mode (name=0x334345 "libgcc_s.so.1", mode=-2147483647) at dl-libc.c:165
#11 0x002d7e38 in init () at ../sysdeps/i386/backtrace.c:44
#12 0x00388e8e in pthread_once () at ../nptl/sysdeps/unix/sysv/linux/i386/pthread_once.S:122
#13 0x002d80a5 in __GI___backtrace (array=0xbfffee90, size=64) at ../sysdeps/i386/backtrace.c:121
#14 0x00241310 in __libc_message (do_abort=2, fmt=0x3393bc "*** glibc detected *** %s: %s: 0x%s ***\n") at ../sysdeps/unix/sysv/linux/libc_fatal.c:180
#15 0x0024be42 in malloc_printerr (action=<optimized out>, str=<optimized out>, ptr=0x80c4eb8) at malloc.c:5007
#16 0x0804aa8f in walkDir (dir=0x8075a60 "/home/olivier/Téléchargements", recursive=1) at dirtraverser.c:251
#17 0x0804aa63 in walkDir (dir=0x80528f8 "/home/olivier", recursive=1) at dirtraverser.c:245
#18 0x0804bdc0 in main (argc=2, argv=0xbffff314) at main.c:246
4

1 に答える 1

1

あなたのxrealloc呼び出し(xrealloc(baseName, buflen << 1);)は間違っています:あなたはその結果をに割り当てていませんbaseNamexrealloc与えたバッファを解放する(そして別のポインタを返す)可能性があるため、結果を割り当てない場合は、バッファを二重に解放することができます。

于 2012-09-20T05:29:13.230 に答える