Beispiel #1
0
def do_callset(base, callset, test_writer):
    print ' '.join([c.__name__ for c in callset])
    test_writer.begin_call_set(callset)

    reporter = progress.ProgressReporter(
        '  {0.npath} paths ({0.ncompath} commutative), {0.nmodel} testcases,' +
        ' {0.nerror} errors', test_writer)

    condlists = collections.defaultdict(list)
    terminated = False
    diverged = set()
    all_internals = []
    for sar in simsym.symbolic_apply(test, base, *callset):
        if sar.type == 'value':
            is_commutative = (len(sar.value.diverge) == 0)
            diverged.update(sar.value.diverge)
            condlists[is_commutative].append(sar.path_condition)
            all_internals.extend(sar.internals)
        test_writer.on_result(sar)
        if not test_writer.keep_going():
            terminated = True
            break

    test_writer.end_call_set()
    reporter.end()

    if terminated:
        print '  enumeration incomplete; skipping conditions'
        return

    conds = collections.defaultdict(lambda: [simsym.wrap(z3.BoolVal(False))])
    for result, condlist in condlists.items():
        conds[result] = condlist

    if True in condlists:
        commute = simsym.symor(condlists[True])
        # Internal variables help deal with situations where, for the
        # same assignment of initial state + external inputs, two
        # operations both can commute and can diverge (depending on
        # internal choice, like the inode number for file creation).
        cannot_commute = simsym.symnot(simsym.exists(all_internals, commute))
        print_cond('can commute', commute)
    else:
        cannot_commute = True

    if False in condlists:
        diverge = simsym.symor(condlists[False])
        print_cond('can not commute; %s' % str_diverge(diverged),
                   simsym.symand([diverge, cannot_commute]))
Beispiel #2
0
        def walk(typ, proj, label):
            """Walk Symbolic type typ.  proj(state) must retrieve a projected
            value of type typ from state.  label must be a tuple that
            can be joined to describe the current projection.

            Returns a list of projection expressions as strings that
            are idempotent for this call.
            """

            # Build idempotence test for this projection
            did_change, did_not_change = [], []
            for (pre, post) in states:
                # Is there a permutation in which this projection did
                # change across this call?
                did_change.append(proj(pre) != proj(post))
                # And is there a permutation in which this projection
                # did not change across this call?
                did_not_change.append(proj(pre) == proj(post))
            idem_expr = simsym.symand(
                [simsym.symor(did_change),
                 simsym.symor(did_not_change)])

            check = xcheck(idem_expr)
            res = []
            if check.is_sat:
                # This projection is idempotent
                res.append(''.join(label))
                # We continue to descend because the more detailed
                # projection information is often useful in
                # understanding why a call is idempotent.

            # Break down the projection further
            if issubclass(typ, simsym.SStructBase):
                # Are any fields idempotent?
                for fname, ftyp in typ._fields.items():
                    res.extend(
                        walk(ftyp,
                             lambda state, fname=fname: getattr(
                                 proj(state), fname),
                             label + ('.' + fname, )))
            elif issubclass(typ, simsym.SMapBase):
                # Is there some map value that is idempotent?  Because
                # of how we construct the final query, this requires
                # it to have the same index in all permutations.
                idx = typ._indexType.var()
                res.extend(
                    walk(typ._valueType, lambda state: proj(state)[idx],
                         label + ('[?]', )))
            return res
Beispiel #3
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)
Beispiel #4
0
    def iused(self, inum):
        dir = SInum.var('dir')
        fn = SFn.var('fn')
        fd = SFdNum.var('fd')
        pid = SPid.var('pid')

        # If we try to simply index into dirmap, its __getitem__
        # won't have access to the supposition that it contains the right
        # key, and throw an exception.  Thus, we use _map directly.
        return simsym.symor([
            ## XXX Directories impl:
            # simsym.exists(dir,
            #     simsym.symand([
            #         self.i_map[dir].isdir,
            #         simsym.exists(fn,
            #             simsym.symand([self.i_map[dir].dirmap.contains(fn),
            #                            self.i_map[dir].dirmap._map[fn] == inum]))])),

            ## XXX Non-directories impl:
            simsym.exists(fn,
                simsym.symand([self.root_dir.contains(fn),
                               self.root_dir._map[fn] == inum])),

            simsym.exists(fd,
                simsym.symand([self.proc0.fd_map.contains(fd),
                               simsym.symnot(self.proc0.fd_map._map[fd].ispipe),
                               self.proc0.fd_map._map[fd].inum == inum])),

            simsym.exists(fd,
                simsym.symand([self.proc1.fd_map.contains(fd),
                               simsym.symnot(self.proc1.fd_map._map[fd].ispipe),
                               self.proc1.fd_map._map[fd].inum == inum])),
            ])
Beispiel #5
0
 def _eq_internal(self, o):
     if type(self) != type(o):
         return NotImplemented
     return simsym.symand([
         self.forgot == o.forgot,
         simsym.symor([self.forgot, self.events == o.events])
     ])
Beispiel #6
0
        def walk(typ, proj, label):
            """Walk Symbolic type typ.  proj(state) must retrieve a projected
            value of type typ from state.  label must be a tuple that
            can be joined to describe the current projection.

            Returns a list of projection expressions as strings that
            are idempotent for this call.
            """

            # Build idempotence test for this projection
            did_change, did_not_change = [], []
            for (pre, post) in states:
                # Is there a permutation in which this projection did
                # change across this call?
                did_change.append(proj(pre) != proj(post))
                # And is there a permutation in which this projection
                # did not change across this call?
                did_not_change.append(proj(pre) == proj(post))
            idem_expr = simsym.symand([simsym.symor(did_change),
                                       simsym.symor(did_not_change)])

            check = xcheck(idem_expr)
            res = []
            if check.is_sat:
                # This projection is idempotent
                res.append(''.join(label))
                # We continue to descend because the more detailed
                # projection information is often useful in
                # understanding why a call is idempotent.

            # Break down the projection further
            if issubclass(typ, simsym.SStructBase):
                # Are any fields idempotent?
                for fname, ftyp in typ._fields.items():
                    res.extend(walk(ftyp,
                                    lambda state, fname=fname:
                                    getattr(proj(state), fname),
                                    label + ('.' + fname,)))
            elif issubclass(typ, simsym.SMapBase):
                # Is there some map value that is idempotent?  Because
                # of how we construct the final query, this requires
                # it to have the same index in all permutations.
                idx = typ._indexType.var()
                res.extend(walk(typ._valueType,
                                lambda state: proj(state)[idx],
                                label + ('[?]',)))
            return res
Beispiel #7
0
    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}
Beispiel #8
0
def test(base, *calls):
    try:
        all_s = []
        all_r = []

        for callseq in itertools.permutations(range(0, len(calls))):
            s = base()
            r = {}
            for idx in callseq:
                r[idx] = calls[idx](s, chr(idx + ord('a')))
            all_s.append(s)
            all_r.append(r)

        diverge = ''
        if simsym.symor([all_r[0] != r for r in all_r[1:]]):
            diverge = diverge + 'r'
        if simsym.symor([all_s[0] != s for s in all_s[1:]]):
            diverge = diverge + 's'
        return diverge
    except PreconditionFailure:
        return None
Beispiel #9
0
 def read(self, fd, 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 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]
         if pipe.data.len() == 0:
             otherfd = SFdNum.var('otherfd')
             if simsym.symor([
                     simsym.exists(
                         otherfd,
                         simsym.symand([
                             self.proc0.fd_map.contains(otherfd),
                             self.proc0.fd_map._map[otherfd].ispipe,
                             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,
                             self.proc1.fd_map._map[otherfd].pipewriter,
                             self.proc1.fd_map._map[otherfd].pipeid ==
                             pipeid
                         ]))
             ]):
                 return {'r': -1, 'errno': errno.EAGAIN}
             else:
                 # XXX The above condition can always be satisfied
                 # by making up some other FD, but testgen may
                 # never see that FD, so the real test may not
                 # reflect its presence.
                 return {'r': 0}
         d = pipe.data[0]
         pipe.data.shift()
         return {'r': DATAVAL_BYTES, 'data': d}
     off = self.getproc(pid).fd_map[fd].off
     r = self.iread(self.getproc(pid).fd_map[fd].inum, off)
     if 'data' in r:
         self.getproc(pid).fd_map[fd].off = off + 1
     return r
Beispiel #10
0
    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}
Beispiel #11
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)
Beispiel #12
0
    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}
Beispiel #13
0
    def iused(self, inum):
        dir = SInum.var('dir')
        fn = SFn.var('fn')
        fd = SFdNum.var('fd')
        pid = SPid.var('pid')

        # If we try to simply index into dirmap, its __getitem__
        # won't have access to the supposition that it contains the right
        # key, and throw an exception.  Thus, we use _map directly.
        return simsym.symor([
            ## XXX Directories impl:
            # simsym.exists(dir,
            #     simsym.symand([
            #         self.i_map[dir].isdir,
            #         simsym.exists(fn,
            #             simsym.symand([self.i_map[dir].dirmap.contains(fn),
            #                            self.i_map[dir].dirmap._map[fn] == inum]))])),

            ## XXX Non-directories impl:
            simsym.exists(
                fn,
                simsym.symand([
                    self.root_dir.contains(fn), self.root_dir._map[fn] == inum
                ])),
            simsym.exists(
                fd,
                simsym.symand([
                    self.proc0.fd_map.contains(fd),
                    simsym.symnot(self.proc0.fd_map._map[fd].ispipe),
                    self.proc0.fd_map._map[fd].inum == inum
                ])),
            simsym.exists(
                fd,
                simsym.symand([
                    self.proc1.fd_map.contains(fd),
                    simsym.symnot(self.proc1.fd_map._map[fd].ispipe),
                    self.proc1.fd_map._map[fd].inum == inum
                ])),
        ])
Beispiel #14
0
 def read(self, fd, 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 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]
         if pipe.data.len() == 0:
             otherfd = SFdNum.var('otherfd')
             if simsym.symor([
                 simsym.exists(otherfd,
                     simsym.symand([self.proc0.fd_map.contains(otherfd),
                                    self.proc0.fd_map._map[otherfd].ispipe,
                                    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,
                                    self.proc1.fd_map._map[otherfd].pipewriter,
                                    self.proc1.fd_map._map[otherfd].pipeid == pipeid]))]):
                 return {'r': -1, 'errno': errno.EAGAIN}
             else:
                 # XXX The above condition can always be satisfied
                 # by making up some other FD, but testgen may
                 # never see that FD, so the real test may not
                 # reflect its presence.
                 return {'r': 0}
         d = pipe.data[0]
         pipe.data.shift()
         return {'r': DATAVAL_BYTES, 'data': d}
     off = self.getproc(pid).fd_map[fd].off
     r = self.iread(self.getproc(pid).fd_map[fd].inum, off)
     if 'data' in r:
         self.getproc(pid).fd_map[fd].off = off + 1
     return r
Beispiel #15
0
    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}
Beispiel #16
0
z3printer._PP.max_lines = float('inf')
for (base, ncomb, projections, calls) in tests:
    module_testcases = []
    projected_calls = list(calls)
    for p in projections:
        for c in calls:
            projected_calls.append(projected_call(p, projections[p], c))
    for callset in itertools.combinations_with_replacement(projected_calls, ncomb):
        print ' '.join([c.__name__ for c in callset])
        rvs = simsym.symbolic_apply(test, base, *callset)
        conds = collections.defaultdict(lambda: simsym.wrap(z3.BoolVal(False)))
        for cond, res in simsym.combine(rvs):
            conds[res] = cond

        pc = simsym.simplify(conds[''])
        pr = simsym.simplify(simsym.symor([conds['r'], conds['rs']]))
        ps = simsym.simplify(conds['s'])

        ex_pc = simsym.exists(simsym.internals(), pc)
        nex_pc = simsym.symnot(ex_pc)
        print "nex_pc", nex_pc
        ex_pr = simsym.exists(simsym.internals(), pr)
        nex_pr = simsym.symnot(ex_pr)
        ps2 = simsym.symand([ps, nex_pc, nex_pr])

        ps_ex_pr = simsym.symand([ps, ex_pr])
        pr2 = simsym.symand([simsym.symor([pr, ps_ex_pr]), nex_pc])

        ps_ex_pc = simsym.symand([ps, ex_pc])
        pr_ex_pc = simsym.symand([pr, ex_pc])
        pc2 = simsym.symor([pc, ps_ex_pc, pr_ex_pc])
Beispiel #17
0
def test_callset(base, callset, monitors, check_conds=False, print_conds=False):
    """Test the SIM-commutativity of a call set.

    base must be a class type for the system state.  calls must be the
    unbound methods of base to test for SIM commutativity.  As the
    test proceeds, this will invoke the appropriate methods of the
    ExecutionMonitorBase instances in monitors.  The caller is
    responsible for calling the 'finish' method of the monitors after
    all callsets are done.

    If check_conds is true, check commutativity conditions for
    sat/unsat and report this.  If print_conds is true, print
    commutativity conditions.  If print_conds is "simplify", use
    ctx-solver-simplify to further simplify conditions.
    """

    monitor = MetaMonitor([StatMonitor()] + monitors)

    print " ".join([c.__name__ for c in callset])
    monitor.begin_call_set(callset)

    reporter = progress.ProgressReporter("  " + monitor.get_progress_format(), monitor)

    condlists = collections.defaultdict(list)
    terminated = False
    diverged = set()
    all_internals = []
    for sar in simsym.symbolic_apply(test, base, *callset):
        if sar.type == "value":
            is_commutative = len(sar.value.diverge) == 0
            diverged.update(sar.value.diverge)
            condlists[is_commutative].append(sar.path_condition)
            all_internals.extend(sar.internals)
        monitor.on_path(sar)
        if monitor.stop_call_set():
            terminated = True
            break

    monitor.end_call_set()
    reporter.end()

    if terminated:
        print "  enumeration incomplete; skipping conditions"
        return

    conds = collections.defaultdict(lambda: [simsym.wrap(z3.BoolVal(False))])
    for result, condlist in condlists.items():
        conds[result] = condlist

    if True in condlists:
        commute = simsym.symor(condlists[True])
        # Internal variables help deal with situations where, for the
        # same assignment of initial state + external inputs, two
        # operations both can commute and can diverge (depending on
        # internal choice, like the inode number for file creation).
        cannot_commute = simsym.symnot(simsym.exists(all_internals, commute))
        print_cond("can commute", commute, check_conds, print_conds)
    else:
        cannot_commute = True

    if False in condlists:
        diverge = simsym.symor(condlists[False])
        print_cond(
            "can not commute; %s" % ", ".join(map(str, diverged)),
            simsym.symand([diverge, cannot_commute]),
            check_conds,
            print_conds,
        )
Beispiel #18
0
    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}
Beispiel #19
0
 def _eq_internal(self, o):
     if type(self) != type(o):
         return NotImplemented
     return simsym.symand([self.forgot == o.forgot,
                           simsym.symor([self.forgot,
                                         self.events == o.events])])