const bigint = TYPE("struct Bigint *")
const ALLOC = 0
const FREED = 1
const PARAM_MARK = 2

function err(msg, line) {
  if(line != 815 && line != 790 && line != 948 && line != 2697 && line != 3064) {
    graph("/tmp/error.dot")
    error(msg + ". See /tmp/error.dot")
  } else {
    print(msg)
  }
}

function uno_check(vars, state, line) {
//   if(select("mult"))
//     display(vars)
  if (select("", [PARAM, bigint])) {
    mark(ALLOC)
    mark(PARAM_MARK)
  } else if (select("", [FCALL, bigint])) {
    if(select("", [DEF], [FCALL])) {
      var v;
      if(match(ALLOC)) {
        v = _selected[0];
        if(!v)
          err("I got too confused", line)
        // it's ok if is like var = do_something(var), because then old mem is cleaned up
        // by do_something
        if(!select(v.name, [USE], [DEF]))
          err(v.name + " is already allocated", line)
      } else {
        select("", [DEF], [FCALL])
        mark(ALLOC)
        unmark(FREED)
        v = _selected[0]
      }
      print(v.name + " marked Allocated")
    }
  } else if (select("", [PARAM_OF("Bfree")])) {
    if(match(ALLOC)) {
      unmark(ALLOC)
      mark(FREED)
    }
    else {
      var v = _selected[0].name;
      display(v)
      if(match(FREED))
        err("Double free of "+ v)
      
      if(!known_zero()) {
        list()
        print(v + " is not allocated", line)
      }
    }
    // now do a=b type things...where if b is ALLOCed then a becomes so transitively
  } else if (select("", [], [FCALL])) {
    if(select("", [USE, bigint], [DEF])) {
      if(match(ALLOC)) {
        var v = _selected[0].name
        if(select("", [DEF], [USE])) {
          mark(ALLOC)
          print(_selected[0].name + " in allocated from " + v)
        }
      }
    }
  }
}

function path_end(state) {
  if (marked(ALLOC))
  {
    const alloc_len = _selected.length
    //if the allocated vars match escaping vars, we are good
    if(match(PARAM_MARK)) {
      print(alloc_len == _selected.length);
      if(alloc_len == _selected.length)
        return
    }
    if(!known_zero() && !known_global()) {
      list()
      err("malloc without free")
    }
  } // print("finished")
}