如果这是堆溢出导致我的程序崩溃,我该如何正确处理内存分配?

时间:2016-02-18 03:01:16

标签: c debugging memory-management file-io heap-memory

我试图编写一个程序来搜索文件中的模式并用一些子字符串替换它们。本质上,我将修改后的文本写入临时文件,删除原始文件,并将临时文件重命名为原始文件名。我已经在单个文件上逐个测试了这个,这似乎工作得很好。

下一步是递归地做事情,当它遍历一些文件,并按原样修改它们时,它到达一个点(在几次调用replaceline()之后),我得到这个错误。

*** Error in `/someplace/a.out': double free or corruption (top): 0x0000000000614090 ***

所以我想在gdb中检查一下,我很难理解:

Program received signal SIGABRT, Aborted.
0x00007ffff7a4bcc9 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56      ../nptl/sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) backtrace
#0  0x00007ffff7a4bcc9 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1  0x00007ffff7a4f0d8 in __GI_abort () at abort.c:89
#2  0x00007ffff7a88394 in __libc_message (do_abort=do_abort@entry=1,
    fmt=fmt@entry=0x7ffff7b96b28 "*** Error in `%s': %s: 0x%s ***\n") at ../sysdeps/posix/libc_fatal.c:175
#3  0x00007ffff7a9466e in malloc_printerr (ptr=<optimized out>,
    str=0x7ffff7b96c38 "double free or corruption (top)", action=1) at malloc.c:4996
#4  _int_free (av=<optimized out>, p=<optimized out>, have_lock=0) at malloc.c:3840
#5  0x00007ffff7a82ae5 in _IO_new_fclose (fp=0x614090) at iofclose.c:85
#6  0x0000000000400fa8 in replaceline (path=0x7fffffffdff0 "./toast/toast3/tt", patternoo=0x401357 "dime",
    replacearoo=0x401352 "lime") at testrep7.c:91
#7  0x00000000004011c5 in recursiveWalk (pathName=0x7fffffffe440 "./toast/toast3", level=1) at testrep7.c:129
#8  0x000000000040118a in recursiveWalk (pathName=0x40135c "./toast", level=0) at testrep7.c:125
#9  0x000000000040122c in main (argc=2, argv=0x7fffffffe958) at testrep7.c:139
(gdb) frame 2
#2  0x00007ffff7a88394 in __libc_message (do_abort=do_abort@entry=1,
    fmt=fmt@entry=0x7ffff7b96b28 "*** Error in `%s': %s: 0x%s ***\n") at ../sysdeps/posix/libc_fatal.c:175
175     ../sysdeps/posix/libc_fatal.c: No such file or directory.

据我所知,这与内存分配不良或某些指针无关?如果是这样,有人能指出我应该在哪做这个吗?

我也可能不止一次删除文件?这就是我从查找什么&#34;双重免费腐败&#34;可能意味着。

据我所知,我的递归步行效果很好,因为它输出了我想要在replaceline()中使用的路径。

我决定包含整个代码,以防错误与replaceline()以外的内容有关,尽管我确实认为这是出错的地方。如果代码太多,我会道歉,但我并不完全确定我已经设法找到某些功能的问题。谢谢。

#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>
#include <libgen.h>

int delete(char* file){

    int status;
    status = remove(file);
}

void renamefile(char* old, char* new){
   int ret;

   ret = rename(old, new);

   if(ret == 0) {
      printf("%s renamed to %s\n", old, new);
   }
   else {
      printf("Error: unable to rename %s\n", old);
        printf("NO %s", strerror(EACCES));
   }
}


char *replace_str(char *str, char *orig, char *rep)
{
  static char buffer[4096];
  char *p;

  if(!(p = strstr(str, orig)))  
    return str;

  strncpy(buffer, str, p-str); 
  buffer[p-str] = '\0';

  sprintf(buffer+(p-str), "%s%s", rep, p+strlen(orig));

  return buffer;
}


void replaceline(char* path, char* patternoo, char* replacearoo){

    char buff[BUFSIZ];      // the input line
    char newbuff[BUFSIZ];   // the results of any editing

   char pattern[200];
    strcpy(pattern, patternoo);

   char replace[200];
    strcpy(replace, replacearoo);

    FILE *in, *out;
     char newstr[200];


    //getbases
    char basec[200];
    char dname[200];
    int found = 0;

    strcpy(basec, path);
    strcpy(dname, dirname(basec));

    strcat(dname, "/loot");

    in = fopen( path, "r" );
    out= fopen( dname, "w" );

    while ( fgets( buff, BUFSIZ, in ) != NULL ) {
        if ( strstr( buff, pattern ) != NULL ) {

             //THIS IS WHERE WE DO THE THING 
                strcpy(newbuff, replace_str(buff, pattern, strcat(replace,pattern)));             
              found = 1;

        } else {
              strcpy( newbuff, buff );
              printf("nothin to do\n");
        }
        fputs( newbuff, out );
            fclose( in );
            fclose( out );
            delete(path); // delete original
            renamefile(dname, path); //the temp is now new
    }

    if(found == 0){ 
    fclose( in );
    fclose( out );
    }
}

void recursiveWalk(const char *pathName, int level) {
   DIR *dir;
   struct dirent *entry;

   if (!(dir = opendir(pathName))) {
      fprintf(stderr, "Could not open directory\n");
      return;
   }

   if (!(entry = readdir(dir))) {
      fprintf(stderr, "Could not read directory\n");
      return;
   }

   do {
      char path[1024];
      int len = snprintf(path, sizeof(path)-1, "%s/%s", pathName, entry->d_name); // get depth
      if (entry->d_type == DT_DIR) { // found subdirectory
         // skip hidden paths
         if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
            continue;
         }
         recursiveWalk(path, level + 1);
      }
      else { // files
         fprintf(stdout, "%s \n", path); // HERE!!!!!!!!!!!
            replaceline(path,"dime", "lime");
      }
   } while ((entry = readdir(dir)));

   closedir(dir);
}

int main(int argc, char* argv[]){

//  replaceline("./toast/nodime","dime", "lime");
    recursiveWalk("./toast", 0);

    return 0;
}

1 个答案:

答案 0 :(得分:1)

功能中的

replaceline()

我怀疑代码正在关闭文件并且早期删除源文件。

建议在循环中读取/修改/写入,直到文件结束,

然后关闭文件并删除源文件。

如果文件包含要替换的字符串,则以下遍历循环将尝试从已关闭的文件中读取。

建议不要关闭,删除,重命名文件,直到读完整个文件为止。退出while循环后