2014-11-08 3 views
0

Я писал виртуальную машину, и я заметил, что некоторые странные вещи произошли, хотя я писал эту функцию много лет назад. Во всяком случае, моя виртуальная машина читает файл, как это:Странное поведение с файлом C IO

0002 000A 0001 0004 0000 

Однако, когда я не есть какие-либо пробелы после 0000 или новой строки ... он выходит из строя. Другая действительно странная вещь, которая заставляет меня поверить, что это не Загрузка файла, это то, что когда вы удаляете 0000 из файла и пробелы ... это работает ?! Я попытался запустить его через GDB, но он действительно работает - по-видимому, это называется heisenbug или что-то в этом роде. Я думаю, что это связано с загрузкой файлов, которые вы можете увидеть в this function here on github, или просто прочитайте фрагмент ниже.

void load_program(vm *self) { 
    FILE *file = fopen("testing.ayy", "r"); 

    if (file != NULL) { 
     if (fseek(file, 0, SEEK_END) == 0) { 
      long file_size = ftell(file); 
      if (file_size == -1) { 
       perror("could not read filesize\n"); 
       exit(1); 
      } 
      self->source = malloc(sizeof(char) * file_size); 

      if (fseek(file, 0, SEEK_SET) != 0) { 
       perror("could not reset file index\n"); 
       exit(1); 
      } 

      size_t file_length = fread(self->source, sizeof(char), file_size, file); 
      if (file_length == 0) { 
       perror("given file is empty\n"); 
       exit(1); 
      } 
      self->source[file_size] = '\0'; 
     } 
     fclose(file); 
    } 
    else { 
     perror("could not read file: \n"); 
     exit(1); 
    } 

    self->source_compact = strdup(self->source); 
    self->source_compact = deblank(self->source_compact); 

    // here we divide because strlen is in characters, 
    // whereas each instruction code should be 4 characters 
    // so we're converting char size to num of instructions 
    self->instructions_size = strlen(self->source_compact)/INSTRUCTION_LENGTH; 

    int i; 
    for (i = 0; i < self->instructions_size; i++) { 
     char *instr = substring(self->source_compact, i); 

     if (strcmp(instr, ERROR_CODE)) { // not equal to NOPE 
      if (self->instructions != NULL) { 
       self->instructions = add_instructions(self->instructions, strtol(instr, NULL, 16)); 
      } 
      else { 
       self->instructions = create_instructions(strtol(instr, NULL, 16)); 
      } 
     } 
    } 

    self->instructions = reverse(self->instructions); 
} 

Но я добавил ссылку GitHub, так как я не уверен, что эта функция; или если это происходит из-за чего-либо, происходящего во всем источнике, поэтому, если кто-нибудь из C-гуру может мне помочь, это было бы блестяще :). Я уверен, что это либо vm.c, либо vm.h, и извините за ужасный код; Я никогда не искал многое в File IO, когда учился (большая ошибка).

+0

'self-> source [file_size] = '\ 0';' вне диапазона доступа. – BLUEPIXY

+0

Должно ли это быть 'file_size - 1', или когда мне нужно сделать malloc (file_size + 1)? – dean

+0

'malloc (sizeof (char) * (file_size + 1)); ' – BLUEPIXY

ответ

1
self->source = malloc(sizeof(char) * file_size); 
... 
self->source[file_size] = '\0'; 

Вам необходимо выделить еще один байт для завершения ноль. Индекс source[file_size] фактически является одним байтом за пределами выделенной памяти. Запись в это место может скрыть некоторые другие переменные или внутренние структуры, используемые malloc(). Сделать это:

self->source = malloc(sizeof(char) * (file_size + 1)); 

или просто:

self->source = malloc(file_size + 1); 

sizeof(char) всегда 1, поэтому он является излишним.

Если вы хотите, чтобы защитить себя в случае, если тип self->source изменений, вы можете использовать:

self->source = malloc ((file_size+1) * sizeof *self->source); 

который автоматически выделяет правильный размер.

Вы должны также проверить, было ли выделение успешным, прежде чем пытаться получить доступ к памяти.

+0

Отлично, я просто сохраняю sizeof (char), так как люди говорят, чтобы сделать это для портативности или нет. – dean

+0

с использованием параметра sizeof * self-> source (что означает, что размер того, что когда-либо был self-> source, указывает на (на данный момент в коде, который не определен), и если sizeof * self-> source больше 1, тогда объем распределения памяти будет расширяться на 2 или 3, или то, что когда-либо возвращается. Вероятно, очень плохая идея добавить выражение sizeof в параметр malloc. – user3629249

+0

@ user3629249: Оператор 'sizeof' заботится только о ** типе ** своего аргумента, и тип должен быть известен в точке назначения. Размер распределения _has to_ будет кратным размеру типа, для которого вы выделяете память. –