def enqueue_proc_prio_queue(self, pid, pprio): simsym.assume(pid >= NULLPROCREF) simsym.assume(pid <= IDLEPROCREF) simsym.assume(pprio >= 0) simsym.assume(pprio <= MAXPROCS) self.qprio.create(pid) self.qprio[pid] = pprio if procs_prev.empty(): # empty queue procs_prev.create(pid) procs_prev[pid] = NULLPROCREF procs_next.create(pid) procs_next[pid] = NULLPROCREF else: # find the right place to add the new pid in pcut = PRef.var() simsym.assume(simsym.exists(pcut, symand(qprio.contains(pcut), symor(symand(qprio[pcut] >= pprio, symor(qprio[proces_prev[pcut]] < pprio, proces_prev[pcut] == NULLPROCREF), symand(qprio[pcut] <= pprio, symor(qprio[proces_next[pcut]] > pprio, proces_next[pcut] == NULLPROCREF))))))) # find a process with higer priority if qprio[proces_prev[pcut]] < pprio or proces_prev[pcut] == NULLPROCREF: # --- < pid <= pcut <= --- procs_prev.create(pid) procs_prev[pid] = proces_prev[pcut] procs_next.create(pid) procs_next[pid] = pcut proces_prev[pcut] = pid # find a process with lower priority else: # --- <= pcut <= pid < --- procs_next.create(pid) procs_next[pid] = proces_next[pcut] procs_prev.create(pid) procs_prev[pid] = pcut proces_next[pcut] = pid
def write(self, fd, databyte, pid): self.add_selfpid(pid) if not self.getproc(pid).fd_map.contains(fd): return {'r': -1, 'errno': errno.EBADF} if self.getproc(pid).fd_map[fd].ispipe: if not self.getproc(pid).fd_map[fd].pipewriter: return {'r': -1, 'errno': errno.EBADF} pipeid = self.getproc(pid).fd_map[fd].pipeid pipe = self.pipes[pipeid] otherfd = SFdNum.var('otherfd') if simsym.symnot(simsym.symor([ simsym.exists(otherfd, simsym.symand([self.proc0.fd_map.contains(otherfd), self.proc0.fd_map._map[otherfd].ispipe, simsym.symnot(self.proc0.fd_map._map[otherfd].pipewriter), self.proc0.fd_map._map[otherfd].pipeid == pipeid])), simsym.exists(otherfd, simsym.symand([self.proc1.fd_map.contains(otherfd), self.proc1.fd_map._map[otherfd].ispipe, simsym.symnot(self.proc1.fd_map._map[otherfd].pipewriter), self.proc1.fd_map._map[otherfd].pipeid == pipeid]))])): # XXX This condition has the same problem as the one # in read. return {'r': -1, 'errno': errno.EPIPE} simsym.assume(pipe.data.len() < DATA_MAX_LEN) pipe.data.append(databyte) return {'r': DATAVAL_BYTES} off = self.getproc(pid).fd_map[fd].off self.getproc(pid).fd_map[fd].off = off + 1 return self.iwrite(self.getproc(pid).fd_map[fd].inum, off, databyte)
def reorder_proc_prio_queue(pid, newprio): simsym.assume(pid >= NULLPROCREF) simsym.assume(pid <= IDLEPROCREF) simsym.assume(qprio.contains(pid)) simsym.assume(newprio >= 0) simsym.assume(newprio <= MAXPROCS) self.remove_prio_queue_elem(pid) self.enqueue_proc_prio_queue(pid, newprio)
def __init__(self): self.fn_to_ino = symtypes.anyDictOfIntToInt('Fs.dir') self.ino_to_data = symtypes.anyDictOfIntToInt('Fs.idata') self.numifree = simsym.SInt.any('Fs.numifree') simsym.assume(self.numifree >= 0) fn = simsym.unwrap(simsym.SInt.any('fn')) simsym.assume(z3.ForAll(fn, z3.Implies(self.fn_to_ino._valid[fn], self.ino_to_data._valid[self.fn_to_ino._map[fn]])))
def iread(self, inum, off, time=None): simsym.assume(off >= 0) if off >= self.i_map[inum].data._len: return {'r': 0} if time is None: time = STime.var('internal_time*') if time is not False: simsym.assume(time >= self.i_map[inum].atime) self.i_map[inum].atime = time return {'r': DATAVAL_BYTES, 'data': self.i_map[inum].data[off]}
def unlink(self, pn): internal_time = STime.var('internal_time*') _, dirmap, pnlast = self.nameiparent(pn) if not dirmap.contains(pnlast): return {'r': -1, 'errno': errno.ENOENT} inum = dirmap[pnlast] del dirmap[pnlast] self.i_map[inum].nlink = self.i_map[inum].nlink - 1 simsym.assume(internal_time >= self.i_map[inum].ctime) self.i_map[inum].ctime = internal_time return {'r': 0}
def make_unready(self, pid): simsym.assume(pid >= NULLPROCREF) simsym.assume(pid <= IDLEPROCREF) self.lck.lock() if is_current_proc(pid): self.ctxt.save_state() self.run_next_process() self.lck.unlock() else: self.readyqp.remove_prio_queue_elem(pid) self.lck.unlock()
def remove_element(self, x): i = simsym.SInt.var() simsym.assume(simsym.exists(i, simsym.symand(self.elts.len() > i, self.elts[i] == x))) newElts = symtypes.tlist(simsym.SInt, APref).var() k = simsym.SInt.var() k = 0 while k < self.elts.len(): if k != i: newElts.append(elts[k]) k = k + 1 self.elts = newElts
def next_from_proc_prio_queue(self): simsym.assume phead = PRef.var() simsym.assume(simsym.exists(phead, procs_prev[phead] == NULLPROCREF)) if (procs_next[phead] != NULLPROCREF): procs_prev[procs_next[phead]] = NULLPROCREF # is this the correct way to delete an element from the tdict? del procs_next[phead] del procs_prev[phead] del qprio[phead] return phead;
def link(self, oldpn, newpn): internal_time = STime.var('internal_time*') olddiri, olddirmap, oldlast = self.nameiparent(oldpn) newdiri, newdirmap, newlast = self.nameiparent(newpn) if not olddirmap.contains(oldlast): return {'r': -1, 'errno': errno.ENOENT} if newdirmap.contains(newlast): return {'r': -1, 'errno': errno.EEXIST} inum = olddirmap[oldlast] newdirmap[newlast] = inum self.i_map[inum].nlink = self.i_map[inum].nlink + 1 simsym.assume(internal_time >= self.i_map[inum].ctime) self.i_map[inum].ctime = internal_time return {'r': 0}
def write(self, fd, databyte, pid): self.add_selfpid(pid) if not self.getproc(pid).fd_map.contains(fd): return {'r': -1, 'errno': errno.EBADF} if self.getproc(pid).fd_map[fd].ispipe: if not self.getproc(pid).fd_map[fd].pipewriter: return {'r': -1, 'errno': errno.EBADF} pipeid = self.getproc(pid).fd_map[fd].pipeid pipe = self.pipes[pipeid] otherfd = SFdNum.var('otherfd') if simsym.symnot( simsym.symor([ simsym.exists( otherfd, simsym.symand([ self.proc0.fd_map.contains(otherfd), self.proc0.fd_map._map[otherfd].ispipe, simsym.symnot(self.proc0.fd_map._map[otherfd]. pipewriter), self.proc0.fd_map._map[otherfd].pipeid == pipeid ])), simsym.exists( otherfd, simsym.symand([ self.proc1.fd_map.contains(otherfd), self.proc1.fd_map._map[otherfd].ispipe, simsym.symnot(self.proc1.fd_map._map[otherfd]. pipewriter), self.proc1.fd_map._map[otherfd].pipeid == pipeid ])) ])): # XXX This condition has the same problem as the one # in read. return {'r': -1, 'errno': errno.EPIPE} simsym.assume(pipe.data.len() < DATA_MAX_LEN) pipe.data.append(databyte) return {'r': DATAVAL_BYTES} off = self.getproc(pid).fd_map[fd].off self.getproc(pid).fd_map[fd].off = off + 1 return self.iwrite(self.getproc(pid).fd_map[fd].inum, off, databyte)
def rename(self, src, dst): internal_time = STime.var('internal_time*') srcdiri, srcdirmap, srclast = self.nameiparent(src) dstdiri, dstdirmap, dstlast = self.nameiparent(dst) if not srcdirmap.contains(srclast): return {'r': -1, 'errno': errno.ENOENT} if srcdiri == dstdiri and srclast == dstlast: return {'r': 0} if dstdirmap.contains(dstlast): dstinum = dstdirmap[dstlast] else: dstinum = None dstdirmap[dstlast] = srcdirmap[srclast] del srcdirmap[srclast] if dstinum is not None: self.i_map[dstinum].nlink = self.i_map[dstinum].nlink - 1 simsym.assume(internal_time >= self.i_map[dstinum].ctime) self.i_map[dstinum].ctime = internal_time return {'r': 0}
def iwrite(self, inum, off, databyte, time=None): simsym.assume(off >= 0) ## Avoid overly-long files. fs-test.py caps file size at 16 units. simsym.assume(off < DATA_MAX_LEN) ## XXX Handle sparse files? simsym.assume(off <= self.i_map[inum].data._len) if off == self.i_map[inum].data._len: self.i_map[inum].data.append(databyte) else: self.i_map[inum].data[off] = databyte if time is None: time = STime.var('internal_time*') if time is not False: simsym.assume(time >= self.i_map[inum].mtime) simsym.assume(time >= self.i_map[inum].ctime) self.i_map[inum].mtime = time self.i_map[inum].ctime = time return {'r': DATAVAL_BYTES}
def mmap(self, anon, writable, fixed, va, fd, off, pid): ## TODO: MAP_SHARED/MAP_PRIVATE for files ## -> how to model delayed file read? ## TODO: MAP_SHARED/MAP_PRIVATE for anon (with fork) ## TODO: zeroing anon memory self.add_selfpid(pid) myproc = self.getproc(pid) if not fixed: va = SVa.var('internal_freeva*') simsym.assume(simsym.symnot(myproc.va_map.contains(va))) if not anon: if not myproc.fd_map.contains(fd): return {'r': -1, 'errno': errno.EBADF} if myproc.fd_map[fd].ispipe: # The Linux manpage is misleading, but POSIX is clear # about ENODEV and this is what Linux does. return {'r': -1, 'errno': errno.ENODEV} vma = myproc.va_map.create(va) vma.anon = anon vma.writable = writable if anon: vma.anondata = SDataVal.var() else: simsym.assume(off >= 0) simsym.assume(off % PAGE_DATAVALS == 0) vma.off = off vma.inum = myproc.fd_map[fd].inum # This has to be well-typed, so we use a different variable to # represent VAs. return {'r:va': va}
def open(self, which): fn = simsym.SInt.any('Fs.open[%s].fn' % which) creat = simsym.SBool.any('Fs.open[%s].creat' % which) excl = simsym.SBool.any('Fs.open[%s].excl' % which) trunc = simsym.SBool.any('Fs.open[%s].trunc' % which) if creat: if not self.fn_to_ino.contains(fn): if self.numifree == 0: return ('err', errno.ENOSPC) ino = simsym.SInt.any('Fs.open[%s].ialloc' % which) simsym.add_internal(ino) simsym.assume(simsym.symnot(self.iused(ino))) self.numifree = self.numifree - 1 self.ino_to_data[ino] = 0 self.fn_to_ino[fn] = ino else: if excl: return ('err', errno.EEXIST) if not self.fn_to_ino.contains(fn): return ('err', errno.ENOENT) if trunc: self.ino_to_data[self.fn_to_ino[fn]] = 0 return ('ok',)
def remove_prio_queue_elem(self, pid): simsym.assume(pid >= NULLPROCREF) simsym.assume(pid <= IDLEPROCREF) simsym.assume(qprio.contains(pid)) if (procs_next[pid] != NULLPROCREF): procs_prev[procs_next[pid]] = procs_prev[pid] if (procs_prev[pid] != NULLPROCREF): procs_next[procs_prev[pid]] = procs_next[pid] # is this the correct way to delete an element from the tdict? del procs_next[phead] del procs_prev[phead] del qprio[phead]
def socket(self, domain, type, prot, anyfd, pid): self.add_selfpid(pid) if not ((domain == AF_INET or domain == AF_INET6) and type == SOCK_DGRAM and prot == 0): return {'r': -1, 'errno': errno.EAFNOSUPPORT} internal_ret_fd = SFdNum.var('internal_ret_fd*') simsym.assume(internal_ret_fd >= 0) simsym.assume( simsym.symnot(self.getproc(pid).fd_map.contains(internal_ret_fd))) ## Lowest FD otherfd = SFdNum.var('fd') simsym.assume( simsym.symor([ anyfd, simsym.symnot( simsym.exists( otherfd, simsym.symand([ otherfd >= 0, otherfd < internal_ret_fd, self.getproc(pid).fd_map.contains(otherfd) ]))) ])) sock = self.getproc(pid).fd_map.create(internal_ret_fd) sock.domain = domain sock.type = type sock.prot = prot sock.can_read = True sock.can_write = True sock.is_bound = False sock.is_connected = False sock.local_addr = 0 sock.local_port = 0 sock.remote_addr = 0 sock.remote_port = 0 return {'r': internal_ret_fd}
def queue_front(self): simsym.assume(self.elts.len() > 0) x = self.elts[0] return x
def pipe(self, pid): self.add_selfpid(pid) internal_pipeid = SPipeId.var('internal_pipeid*') xfd = SFdNum.var('xfd') simsym.assume(simsym.symnot(simsym.symor([ simsym.exists(xfd, simsym.symand([self.proc0.fd_map.contains(xfd), self.proc0.fd_map._map[xfd].ispipe, self.proc0.fd_map._map[xfd].pipeid == internal_pipeid])), simsym.exists(xfd, simsym.symand([self.proc1.fd_map.contains(xfd), self.proc1.fd_map._map[xfd].ispipe, self.proc1.fd_map._map[xfd].pipeid == internal_pipeid]))]))) empty_pipe = self.pipes[internal_pipeid] empty_pipe.data._len = 0 ## lowest FD for read end internal_fd_r = SFdNum.var('internal_fd_r*') simsym.assume(internal_fd_r >= 0) simsym.assume(simsym.symnot(self.getproc(pid).fd_map.contains(internal_fd_r))) simsym.assume(simsym.symnot(simsym.exists(xfd, simsym.symand([xfd >= 0, xfd < internal_fd_r, self.getproc(pid).fd_map.contains(xfd)])))) fd_r_data = self.getproc(pid).fd_map.create(internal_fd_r) fd_r_data.ispipe = True fd_r_data.pipeid = internal_pipeid fd_r_data.pipewriter = False ## lowest FD for write end internal_fd_w = SFdNum.var('internal_fd_w*') simsym.assume(internal_fd_w >= 0) simsym.assume(simsym.symnot(self.getproc(pid).fd_map.contains(internal_fd_w))) simsym.assume(simsym.symnot(simsym.exists(xfd, simsym.symand([xfd >= 0, xfd < internal_fd_w, self.getproc(pid).fd_map.contains(xfd)])))) fd_w_data = self.getproc(pid).fd_map.create(internal_fd_w) fd_w_data.ispipe = True fd_w_data.pipeid = internal_pipeid fd_w_data.pipewriter = True return {'r': 0, 'fds[0]': internal_fd_r, 'fds[1]': internal_fd_w}
def _declare_assumptions(self, assume): simsym.assume(self.ip >= 0) simsym.assume(self.memsize >= 0)
def add_selfpid(self, pid): ## XXX hack due to our simplified PID model ## without loss of generality, assume syscall "a" happens in proc0 if str(pid).startswith('a.'): simsym.assume(pid == False)
def open(self, pn, creat, excl, trunc, anyfd, pid): # XXX O_RDONLY, O_WRONLY, O_RDWR self.add_selfpid(pid) internal_time = STime.var('internal_time*') created = False anyfd = False _, pndirmap, pnlast = self.nameiparent(pn) if creat: if not pndirmap.contains(pnlast): internal_alloc_inum = SInum.var('internal_alloc_inum*') simsym.assume(simsym.symnot(self.iused(internal_alloc_inum))) simsym.assume(internal_time >= self.i_map[internal_alloc_inum].atime) simsym.assume(internal_time >= self.i_map[internal_alloc_inum].mtime) simsym.assume(internal_time >= self.i_map[internal_alloc_inum].ctime) inode = self.i_map[internal_alloc_inum] inode.data._len = 0 inode.nlink = 1 inode.atime = inode.mtime = inode.ctime = internal_time pndirmap[pnlast] = internal_alloc_inum created = True else: if excl: return {'r': -1, 'errno': errno.EEXIST} if not pndirmap.contains(pnlast): return {'r': -1, 'errno': errno.ENOENT} inum = pndirmap[pnlast] if trunc: if not created: simsym.assume(internal_time >= self.i_map[inum].mtime) simsym.assume(internal_time >= self.i_map[inum].ctime) self.i_map[inum].mtime = internal_time self.i_map[inum].ctime = internal_time self.i_map[inum].data._len = 0 internal_ret_fd = SFdNum.var('internal_ret_fd*') simsym.assume(internal_ret_fd >= 0) simsym.assume(simsym.symnot(self.getproc(pid).fd_map.contains(internal_ret_fd))) ## Lowest FD otherfd = SFdNum.var('fd') simsym.assume(simsym.symor([anyfd, simsym.symnot(simsym.exists(otherfd, simsym.symand([otherfd >= 0, otherfd < internal_ret_fd, self.getproc(pid).fd_map.contains(otherfd)])))])) fd_data = self.getproc(pid).fd_map.create(internal_ret_fd) fd_data.inum = inum fd_data.off = 0 fd_data.ispipe = False return {'r': internal_ret_fd}
def __init__(self): self.elems = symtypes.anyListOfInt('Pipe.elems') self.nread = simsym.SInt.any('Pipe.nread') simsym.assume(self.nread >= 0) simsym.assume(self.nread <= self.elems.len())
def dec(self): simsym.assume(self.counter > 0) self.counter = self.counter - 1
def prio_of_proc_in_proc_prio_queue(self, pid): simsym.assume(pid >= NULLPROCREF) simsym.assume(pid <= IDLEPROCREF) simsym.assume(qprio.contains(pid)) return self.qprio[pid]
def is_in_proc_prio_queue(self): simsym.assume(pid >= NULLPROCREF) simsym.assume(pid <= IDLEPROCREF) return self.procs_prev.contains(pid)
def is_current_proc(self, p): simsym.assume(pid >= NULLPROCREF) simsym.assume(pid <= IDLEPROCREF) return self.currentp == p
def make_current(self, pid): simsym.assume(pid >= NULLPROCREF) simsym.assume(pid <= IDLEPROCREF) self.currentp = pid
def enqueue_buffer(self, buffer, databyte): simsym.assume(buffer.data.len() < DATA_MAX_LEN) buffer.data.append(databyte)
def pipe(self, pid): self.add_selfpid(pid) internal_pipeid = SPipeId.var('internal_pipeid*') xfd = SFdNum.var('xfd') simsym.assume( simsym.symnot( simsym.symor([ simsym.exists( xfd, simsym.symand([ self.proc0.fd_map.contains(xfd), self.proc0.fd_map._map[xfd].ispipe, self.proc0.fd_map._map[xfd].pipeid == internal_pipeid ])), simsym.exists( xfd, simsym.symand([ self.proc1.fd_map.contains(xfd), self.proc1.fd_map._map[xfd].ispipe, self.proc1.fd_map._map[xfd].pipeid == internal_pipeid ])) ]))) empty_pipe = self.pipes[internal_pipeid] empty_pipe.data._len = 0 ## lowest FD for read end internal_fd_r = SFdNum.var('internal_fd_r*') simsym.assume(internal_fd_r >= 0) simsym.assume( simsym.symnot(self.getproc(pid).fd_map.contains(internal_fd_r))) simsym.assume( simsym.symnot( simsym.exists( xfd, simsym.symand([ xfd >= 0, xfd < internal_fd_r, self.getproc(pid).fd_map.contains(xfd) ])))) fd_r_data = self.getproc(pid).fd_map.create(internal_fd_r) fd_r_data.ispipe = True fd_r_data.pipeid = internal_pipeid fd_r_data.pipewriter = False ## lowest FD for write end internal_fd_w = SFdNum.var('internal_fd_w*') simsym.assume(internal_fd_w >= 0) simsym.assume( simsym.symnot(self.getproc(pid).fd_map.contains(internal_fd_w))) simsym.assume( simsym.symnot( simsym.exists( xfd, simsym.symand([ xfd >= 0, xfd < internal_fd_w, self.getproc(pid).fd_map.contains(xfd) ])))) fd_w_data = self.getproc(pid).fd_map.create(internal_fd_w) fd_w_data.ispipe = True fd_w_data.pipeid = internal_pipeid fd_w_data.pipewriter = True return {'r': 0, 'fds[0]': internal_fd_r, 'fds[1]': internal_fd_w}
def open(self, pn, creat, excl, trunc, anyfd, pid): # XXX O_RDONLY, O_WRONLY, O_RDWR self.add_selfpid(pid) internal_time = STime.var('internal_time*') created = False anyfd = False _, pndirmap, pnlast = self.nameiparent(pn) if creat: if not pndirmap.contains(pnlast): internal_alloc_inum = SInum.var('internal_alloc_inum*') simsym.assume(simsym.symnot(self.iused(internal_alloc_inum))) simsym.assume( internal_time >= self.i_map[internal_alloc_inum].atime) simsym.assume( internal_time >= self.i_map[internal_alloc_inum].mtime) simsym.assume( internal_time >= self.i_map[internal_alloc_inum].ctime) inode = self.i_map[internal_alloc_inum] inode.data._len = 0 inode.nlink = 1 inode.atime = inode.mtime = inode.ctime = internal_time pndirmap[pnlast] = internal_alloc_inum created = True else: if excl: return {'r': -1, 'errno': errno.EEXIST} if not pndirmap.contains(pnlast): return {'r': -1, 'errno': errno.ENOENT} inum = pndirmap[pnlast] if trunc: if not created: simsym.assume(internal_time >= self.i_map[inum].mtime) simsym.assume(internal_time >= self.i_map[inum].ctime) self.i_map[inum].mtime = internal_time self.i_map[inum].ctime = internal_time self.i_map[inum].data._len = 0 internal_ret_fd = SFdNum.var('internal_ret_fd*') simsym.assume(internal_ret_fd >= 0) simsym.assume( simsym.symnot(self.getproc(pid).fd_map.contains(internal_ret_fd))) ## Lowest FD otherfd = SFdNum.var('fd') simsym.assume( simsym.symor([ anyfd, simsym.symnot( simsym.exists( otherfd, simsym.symand([ otherfd >= 0, otherfd < internal_ret_fd, self.getproc(pid).fd_map.contains(otherfd) ]))) ])) fd_data = self.getproc(pid).fd_map.create(internal_ret_fd) fd_data.inum = inum fd_data.off = 0 fd_data.ispipe = False return {'r': internal_ret_fd}
def remove_first(self): simsym.assume(self.elts.len() > 0) x = self.elts[0] self.elts.shift(1) return x
def _declare_assumptions(self, assume): simsym.assume(self.scnt >= 0) simsym.assume(self.initval >= 0)
def __init__(self): self.elems = symtypes.SBag('UPipe.items') self.nitem = simsym.SInt.any('UPipe.nitem') simsym.assume(self.nitem >= 0)
def del_process(self, pid): simsym.assume(procs[pid] != None) return procs[pid]
def __init__(self): # XXX This name matters since it connects the initial counter # value of different State objects. Will this scale to more # complex state? self.counter = simsym.SInt.any('State.counter') simsym.assume(self.counter >= 0)
def enqueue(self, x): simsym.assume(x > NULLPROCREF) simsym.assume(x < IDLEPROCREF) self.elts.append(x)