Valgrind неверная запись размером 8 - PullRequest
2 голосов
/ 05 февраля 2012

Я экспериментирую со структурами C и придумаю invalid write of size 8, за которым следуют invalid read of size 8 сообщения от valgrind.

Мой код перебирает только аргументы (если argc > 1), и для каждого имени файла он просматривает string и unsigned int, указывающие имя и возраст (struct player).

Это весь код, который у меня есть:

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

struct player {
  char name[20];
  unsigned int age;
};

struct player *player_new_from_stream(FILE * stream){
  struct player *new_player = (struct player*) malloc(sizeof(struct player));
  char *p_name = malloc(20);
  char *p_age = malloc(20);

  if (stream != stdin){
    if (fgets(p_name, 20, stream) != NULL){
      char *p = strrchr(p_name, '\n');
      if (p)
        *p = '\0';
      strcpy(new_player->name, p_name);
    }
    if (fgets(p_age, 20, stream) != NULL)
      new_player->age = atoi(p_age);
  }
  else {
    printf("enter name and age for a player\n");
    gets(p_name);
    gets(p_age);
    strcpy(new_player->name, p_name);
    new_player->age = atoi(p_age);
  }

  free(p_name);
  free(p_age);
  return new_player;
}

void player_inspect(struct player plyr, char* prefix){
  printf("[%s] name: %s\n", prefix, plyr.name);
  printf("[%s] age : %d\n", prefix, plyr.age);
}

int main(int argc, char* argv[]){
  FILE * stream;
  char* argument;
  // below: trying to allocate (argc - 1) pointers
  // valgrind's --show-origins=yes points here for both errors
  struct player **players = malloc(sizeof(int) * (argc - 1)); 
  int i = 1;
  for (; i < argc; i++){
    argument = argv[i];
    if (strcmp("-", argument) != 0){
      if ((stream = fopen(argument, "r")) == NULL) perror("Error opening file");
      else {
        // the next line emits Invalid write of size 8 in valgrind
        players[i-1] = player_new_from_stream(stream);
        fclose(stream);
      }
    } else {
      players[i-1] = player_new_from_stream(stdin);
    }
  }

  i = 0;
  char buffer[15];
  for (; i < argc - 1; i++){
    sprintf(buffer, "%d", i);
    // the next line emits Invalid read of size 8
    player_inspect(*(players[i]), buffer);
    free(players[i]);
  }

  free(players);
  return 0;
}

Что здесь не так? Я хочу вернуть указатель на struct player из player_new_from_stream и упаковать этот указатель в массив players в main().

Ответы [ 3 ]

4 голосов
/ 05 февраля 2012

Это неправильно:

struct player **players = malloc(sizeof(int) * (argc - 1));

Используйте это вместо:

struct player **players = malloc(sizeof(*players) * (argc - 1));

Обратите внимание, что в вашей системе sizeof(int) == 4, а sizeof(struct player *) == 8.

1 голос
/ 05 февраля 2012

Я запустил его под valgrind с допустимыми входными файлами (файлами плеера), скомпилированными с помощью gcc -g, и он не выдал ни одного из этих недопустимых сообщений чтения / записи.

Он также работал для использования stdin.

Однако, когда я запустил его с несуществующими файлами, возникла ошибка чтения на

  i = 0;
  char buffer[15];
  for (; i < argc - 1; i++){
    sprintf(buffer, "%d", i);
    player_inspect(*(players[i]), buffer); // <<HERE
    free(players[i]);
  }

, так как указатель Players [i] был НЕДЕЙСТВИТЕЛЕН из-за указателя на этот индекс массиване устанавливается в случае сбоя вызова fopen.

1 голос
/ 05 февраля 2012

Вам нужно сделать двойное распределение, если вы хотите использовать массив:

struct player **players = malloc(sizeof(struct player*) * (argc - 1));
for (int i=0; i<argc-1;i++)
   player[i] = malloc(sizeof(struct player));
...