c - Valgrind:大小为 8 的无效读/写

标签 c memory memory-management valgrind

我是一名尝试编写目录树的 C 新手。它工作没问题,但 Valgrind 不赞成。我读过关于类似问题的帖子,但似乎无法弄清楚。

我会非常感谢答案,不仅要有一个片段来让它工作,还要解释我做错了什么,这样我以后就不会遇到同样的问题了。关于为什么代码通常不好的反馈也不会被忽视 :)

这些是来自 Valgrind 的错误(乘以处理的项目数量):

==10463== Invalid write of size 8
==10463==    at 0x400C5D: checkDir (dirtree.c:96)
==10463==    by 0x400F53: main (dirtree.c:135)
==10463==  Address 0x51f88d8 is 0 bytes after a block of size 8 alloc'd
==10463==    at 0x4C28F9F: malloc (vg_replace_malloc.c:236)
==10463==    by 0x400BED: checkDir (dirtree.c:93)
==10463==    by 0x400F53: main (dirtree.c:135)

==10463== Invalid read of size 8
==10463==    at 0x4ECFF28: __tz_convert (tzset.c:627)
==10463==    by 0x4ECD728: ctime (ctime.c:32)
==10463==    by 0x401022: main (dirtree.c:147)
==10463==  Address 0x51f88d8 is 0 bytes after a block of size 8 alloc'd
==10463==    at 0x4C28F9F: malloc (vg_replace_malloc.c:236)
==10463==    by 0x400BED: checkDir (dirtree.c:93)
==10463==    by 0x400F53: main (dirtree.c:135)

她的代码(剥离了堆栈代码):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <dirent.h>

#define MAX_PATH_LENGTH 500
#define MAX_ITEM_LENGTH 5000
#define MAX_ITEM_CNT 1000

typedef struct dirent dirent;
typedef struct file_s {
  char *name;
  time_t mtime;
} file_n;
typedef struct itemss {
  int filecnt;
  file_n *files[sizeof(char*)*MAX_ITEM_CNT];
  int dircnt;
  char *dirs[sizeof(char*)*MAX_ITEM_CNT];              
} items;
typedef stack_node_s* stack_s;

void stack_init(stack_s *stack){
    *stack = NULL;
}

/* Pushes item to a stack pointed by parameter stack. Returns 0 if succesful,
 * -1 otherwise.
 */
int stack_push(void *p, stack_s *stack){
    stack_node_s *newitem = malloc(sizeof(stack_node_s));
    if (!newitem) return -1;
    newitem->value = p;
    newitem->next = *stack;
    *stack = newitem;
    return 0;
}

/* Pops item from a stack pointed by parameter stack. Returns pointer to
 * element removed from stack if succesful, null if there is an error or
 * the stack is empty.
 */
void *stack_pop(stack_s *stack){
    if(!*stack) return NULL;
    stack_node_s *freethis = *stack; 
    void *returnp = freethis->value;
    *stack = (*stack)->next;
    free(freethis);
    return returnp;
}

int isDir(char *dirname){
  struct stat stbuf;
  stat(dirname, &stbuf);
  return S_ISDIR(stbuf.st_mode);
}

time_t mtime(char *dirname){
  struct stat stbuf;
  stat(dirname, &stbuf);
  return stbuf.st_mtime;
}

void checkDir(char* path, stack_s **stack, items *list ){
  DIR *stream;
  char fullpath[MAX_PATH_LENGTH];

  if(!(stream = opendir(path))){
    return;
  }
  struct dirent *dir;
  while((dir = readdir(stream))){
    strcpy(fullpath, path);
    strcat(fullpath, "/");
    if(strcmp(dir->d_name, ".") && strcmp(dir->d_name, "..")){
      char *savedpath = (char*) malloc(sizeof(char)*MAX_ITEM_LENGTH);
      strcat(fullpath, dir->d_name);
      strcpy(savedpath,fullpath);
      if(isDir(savedpath)){
    list->dirs[(list->dircnt)++] = savedpath;
    stack_push(savedpath,stack);
      }
      else{
    file_n *new = (file_n*) malloc(sizeof(file_n*));
    list->files[(list->filecnt)] = new;
    (list->files[(list->filecnt)])->name = savedpath;
    (list->files[(list->filecnt)])->mtime = mtime(savedpath);
    (list->filecnt)++;
      }
    }
  }
  closedir(stream);
  char *popped;
  while(popped = (char*)stack_pop(stack)){ 
    checkDir(popped,stack,list);
  }
}

int qsortcbdir(const void* a, const void* b){
    const char **ia = (const char **)a;
    const char **ib = (const char **)b;
    return strcmp(*ia, *ib);
}

int qsortcbfile(const void* a, const void* b){
    const file_n **ia = (const file_n **)a;
    const file_n **ib = (const file_n **)b;
    int timea = (int) (**ia).mtime;
    int timeb = (int) (**ib).mtime;
    if(timea == timeb)
      return strcmp((**ia).name, (**ib).name);
    return timea - timeb;
}

int main(int argc, char* argv[]){
  if(argc != 2){
    printf("Incorrect number of arguments, exiting.\n");
    return -1;
  }
  stack_s stack;
  stack_init(&stack);
  items *list = (items*)malloc(sizeof(items));
  list->dircnt = (list->filecnt = 0);
  memset(list->dirs, 0, sizeof(char*)*MAX_ITEM_CNT);
  memset(list->files, 0, sizeof(char*)*MAX_ITEM_CNT);
  checkDir(argv[1], &stack, list);

  qsort(list->dirs,list->dircnt,sizeof(char*), &qsortcbdir);
  for(int i=0;i < list->dircnt;i++){
    printf("%s\n", list->dirs[i]);
    free(list->dirs[i]);
  }
  printf("---\n");

  qsort(list->files,list->filecnt,sizeof(file_n*), &qsortcbfile);
  for(int i=0;i < list->filecnt;i++){
    printf("path: %s, mtime: %s", (list->files[i])->name, ctime(&((list->files[i])->mtime)));
    free((list->files[i])->name);
    free(list->files[i]);
  }
  free(list);

  return EXIT_SUCCESS;
}

最佳答案

您只为指向 file_n 的指针分配了足够的空间:

file_n *new = (file_n*) malloc(sizeof(file_n*));

正确的方法是这样做(并省略类型转换,这是不必要的):

file_n *new = malloc(sizeof(file_n));

关于c - Valgrind:大小为 8 的无效读/写,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9950780/

相关文章:

c - 进程结束/死亡时共享 POSIX 对象清理

java - 使用 volatile 关键字时出现内存一致性错误的示例?

java - JVM 中有多少个对象是太多了?

memory - Cuda 合并内存加载行为

c++ - 从 Qt 类派生的用户定义类中的内存所有权

php - 使用 PHP/Drupal 处理大型数据集

c - 通过链表迭代导致段错误

c++ - 在 C 或 C++ 中,我应该根据 NULL/nullptr 检查指针参数吗?

c - 这两个变量在内存中的处理方式有何不同

c - 如何在 C 中打印非 ASCII 字符