Why does this interpreter results in a segmentation fault?

112 Views Asked by At

I am trying to write a brainf*ck Interpreter in C. The current pointer, the array and the length of the array are given in a struct.

The interpreter method receives pointers to the array struct and the brainf*ck instruction as a string. If the instruction is valid the method may return 1, else 0.

I do not understand where this error might occur. Perhaps a wrong pointer.

struct Array {
  size_t array_len;
  uint8_t* array;

  uint8_t* cur;
};

int brainfuckInterpreter(struct Array* state, const char* program) {
  
  uint8_t ptr = *(state->cur);    // loading the the pointer for the array
  char prog_curr;
  uint8_t brk_count;                // bracket-counter for jump commands
  uint8_t i = 0;                  // counter for the array
  while( i < state->array_len-1){
     
    if(ptr > state->array_len || ptr < 0){        // check if the array-pointer is within the array
      return 0;
    }

      prog_curr = *(program+i++);                   // Loading the next command of the string program

      switch (prog_curr){
      case '.': putchar( state->array[ptr]); break;
      case '+': {state->array[ptr]++;} break;
      case '-': {state->array[ptr]--;} break;
      case '>': {
          if(ptr >= state->array_len){
            return 0;
          }else {
            ptr++;
          }
      } break;
      case '<': {
          if(ptr < 0){
            return 0;
          }else {
        ptr--;
      } break;
      }
      case '[': {
          if( state->array[ptr] == 0 ){
            brk_count = 0;
            prog_curr = *(program + ptr);
            do{
              if(prog_curr == '['){brk_count++;};
              if(prog_curr == ']'){brk_count--;};
              if(brk_count != 0){
                ptr++;
                prog_curr = *(program+ptr);
              }
            } while (brk_count != 0);
        }else{
          ptr++;
        }
      } break;
      case ']': {
        if(state->array[ptr] == 0){
          brk_count = 0;
          prog_curr = *(program + ptr);
          do{
            if(prog_curr == '['){brk_count--;};
            if(prog_curr == ']'){brk_count++;};
            if( brk_count != 0){
              ptr--;
              prog_curr = *(program + ptr);
            }  
          } while (brk_count != 0);
            
        }else{
          ptr++;
        }
      } break;
      default: {ptr++;} break;   // all other characters are getting ignored
    } 
  }
  return 1;
}
1

There are 1 best solutions below

0
Daniel Cristofani On

Several problems.

You confuse ptr with i; you start out using ptr as location in the array and i as location in the program, but you compare i with state->array_len rather than with the length of the program, and then in your later bracket-handling code you use "ptr" for both variables.

(Also, your bracket code assumes that the program index still points to the current command, but you auto-incremented i at the start of the loop.)

(And the default action for non-commands shouldn't increment ptr OR i because you very reasonably aren't leaving that up to individual commands to do, so doing it explicitly makes it happen twice. Same with the "else" cases for the bracket handling, at least if you change to incrementing i at the very end of your outermost while loop or make it a for loop.)

Also: by defining ptr and i and *cur as bytes you limit the length of the brainfuck array and of your program to 256 bytes, which is not okay. Offhand I'd suggest 16 megabytes as a good limit.

You also have the test in your ']' code reversed (should jump back on NONzero), and you have an off-by-one checking for "ptr > state->array_len" rather than "ptr >= state->array_len".