2014-11-08 3 views
0

나는 가상 머신을 작성해 왔으며 몇 년 전에이 함수를 작성 했음에도 이상한 일이 발생했다는 것을 알았다. 어쨌든, 내 가상 머신이 같은 파일을 읽 나는 0000 또는 새 줄 뒤에 공백이없는 할 때, 그러나C 파일의 이상한 동작 IO

0002 000A 0001 0004 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]은 실제로 할당 된 메모리의 끝을 1 바이트 초과합니다. 해당 위치에 글을 쓰면 malloc()에서 사용하는 다른 변수 나 내부 구조가 손상 될 수 있습니다.

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

sizeof(char) 항상 1, 그래서 그것은 중복 : 단지

self->source = malloc(sizeof(char) * (file_size + 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' 연산자는 인수의 ** type **에만 관심을 가지며 유형은 할당 시점에서 알 수 있어야합니다. 할당의 크기는 메모리를 할당하는 유형의 크기의 배수 여야합니다. –