Example #1
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])),
            ])
Example #2
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)
Example #3
0
 def _eq_internal(self, o):
     if type(self) != type(o):
         return NotImplemented
     return simsym.symand(
         [self.anon == o.anon, self.writable == o.writable,
          simsym.symif(self.anon, self.anondata == o.anondata,
                       simsym.symand([self.off == o.off,
                                      self.inum == o.inum]))])
Example #4
0
 def _eq_internal(self, o):
     if type(self) != type(o):
         return NotImplemented
     return simsym.symand([
         self.anon == o.anon, self.writable == o.writable,
         simsym.symif(
             self.anon, self.anondata == o.anondata,
             simsym.symand([self.off == o.off, self.inum == o.inum]))
     ])
Example #5
0
 def _eq_internal(self, o):
     if type(self) != type(o):
         return NotImplemented
     return simsym.symand(
         [self.ispipe == o.ispipe,
          simsym.symif(self.ispipe,
                       simsym.symand([self.pipeid == o.pipeid,
                                      self.pipewriter == o.pipewriter]),
                       simsym.symand([self.inum == o.inum,
                                      self.off == o.off]))])
Example #6
0
 def _eq_internal(self, o):
     if type(self) != type(o):
         return NotImplemented
     return simsym.symand([
         self.ispipe == o.ispipe,
         simsym.symif(
             self.ispipe,
             simsym.symand(
                 [self.pipeid == o.pipeid,
                  self.pipewriter == o.pipewriter]),
             simsym.symand([self.inum == o.inum, self.off == o.off]))
     ])
Example #7
0
 def __eq__(self, o):
     if self.__class__ != o.__class__:
         return NotImplemented
     # XXX Should this indicate what field is not equal?
     fieldeqs = [getattr(self, field) == getattr(o, field)
                 for field in self.__slots__]
     return simsym.symand(fieldeqs)
Example #8
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])
     ])
Example #9
0
    def xcheck(cond):
        check = simsym.check(simsym.symand([pc, iso_constraint, cond]))
        if check.is_unknown:
            if unknown_count[0] == 0:
                print '  Idempotence unknown:', check.reason
#                print '    ' + str(cond)
            unknown_count[0] += 1
        return check
Example #10
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
Example #11
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}
Example #12
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)
Example #13
0
    def xcheck(cond):
        check = simsym.check(simsym.symand([pc, iso_constraint, cond]))
        if check.is_unknown:
            if unknown_count[0] == 0:
                print '  Idempotence unknown:', check.reason


#                print '    ' + str(cond)
            unknown_count[0] += 1
        return check
Example #14
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}
    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
Example #16
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
                ])),
        ])
Example #17
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
Example #18
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]))
Example #19
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
Example #20
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
Example #21
0
    def condition(self):
        """Return the isomorphism condition."""
        conds = list(self.__conds)

        for rep_map in self.__repmaps.itervalues():
            distinct = []
            for reps in rep_map.itervalues():
                reps = list(reps)
                # Require each representative group to be distinct
                distinct.append(reps[0])
                # Require all expressions within the representative
                # group to be equal
                conds.append(simsym.symeq(*reps))
            if len(distinct) > 1:
                conds.append(simsym.distinct(*distinct))

        return simsym.symand(conds)
Example #22
0
    def condition(self):
        """Return the isomorphism condition."""
        conds = list(self.__conds)

        for rep_map in self.__repmaps.itervalues():
            distinct = []
            for reps in rep_map.itervalues():
                reps = list(reps)
                # Require each representative group to be distinct
                distinct.append(reps[0])
                # Require all expressions within the representative
                # group to be equal
                conds.append(simsym.symeq(*reps))
            if len(distinct) > 1:
                conds.append(simsym.distinct(*distinct))

        return simsym.symand(conds)
Example #23
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}
Example #24
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}
Example #25
0
    def setup_proc(self, pid, fdmap, vamap, pipe_end_fds):
        emit = self.emit
        emit("int fd __attribute__((unused));", "int r __attribute__((unused));")
        for fd, (symfd, inode) in fdmap.items():
            if symfd.ispipe:
                pipe_setup_fd = self.pipes[symfd.pipeid]
                if symfd.pipewriter:
                    pipe_setup_fd += 1
                emit("r = dup2(%d, %d);" % (pipe_setup_fd, fd), 'if (r < 0) setup_error("dup2");')
            else:
                emit(
                    'fd = open("%s", O_RDWR);' % self.inums[symfd.inum].fname,
                    'if (fd < 0) setup_error("open");',
                    "r = lseek(fd, %d, SEEK_SET);" % (inode.offsets[symfd.off]),
                    'if (fd >= 0 && r < 0) setup_error("lseek");',
                    "r = dup2(fd, %d);" % fd,
                    'if (fd >= 0 && r < 0) setup_error("dup2");',
                    "close(fd);",
                )

        # There may be other FDs open to pipes that never came up in the
        # test, but that matter to keep the pipe open.  Check for this
        # possibility for every pipe end.
        for (_, pipewriter), (pipeid, pidcounts) in pipe_end_fds.items():
            # How many of this end are already set up in this process?
            knowncount = pidcounts[pid]
            # Try to find > knowncount distinct instances of this end in
            # this process.
            conds = []
            distinct = []
            sym_fd_map = self.fs.getproc(pid).fd_map
            for i in range(knowncount + 1):
                ofdnum = fs_module.SFdNum.var()
                ofd = sym_fd_map._map[ofdnum]
                conds.extend(
                    [sym_fd_map._valid[ofdnum], ofd.ispipe, ofd.pipeid == pipeid, ofd.pipewriter == pipewriter]
                )
                distinct.append(ofdnum)
            if len(distinct) > 1:
                conds.append(simsym.distinct(*distinct))

            # XXX I've tried to *prove* that the path condition implies
            # there *must* be more FDs for this pipe end, so the decision
            # will stand regardless of choices made by model completion, but
            # I just can't get it to work:
            #  prove(simsym.implies(self.constraint,
            #                       simsym.exists(ofdnums, simsym.symand(conds))))

            result = simsym.check(simsym.symand([self.constraint] + conds))
            if result.is_unknown:
                print "Warning: Unable to check pipe FD existence:", result.reason
            elif result.is_sat:
                # Open up another pipe end
                pipe_setup_fd = self.pipes[pipeid]
                if pipewriter:
                    pipe_setup_fd += 1
                emit("r = dup(%d);" % pipe_setup_fd, 'if (r < 0) setup_error("dup");')

        for va, vainfo in vamap.items():
            if vainfo.anon:
                emit(
                    "init_map_anon(%#x, %d, %d);" % (va, vainfo.writable.val, self.datavals[vainfo.anondata].first_byte)
                )
            else:
                inode = self.inums[vainfo.inum]
                emit(
                    'init_map_file(%#x, %d, "%s", %#x);'
                    % (va, vainfo.writable.val, inode.fname, inode.offsets[vainfo.off])
                )
Example #26
0
        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])

        for msg, cond in (('commute', pc2),
                          ('results diverge', pr2),
                          ('states diverge', ps2)):
            if simsym.check(cond)[0] == z3.unsat:
                continue
            if simsym.check(simsym.symnot(cond))[0] == z3.unsat:
                s = 'any state'
Example #27
0
    def on_path(self, result):
        super(TestWriter, self).on_path(result)

        pathinfo = collections.OrderedDict([
            ('id', '_'.join(self.callset_names) + '_' + result.pathid)])
        self.model_data_callset[result.pathid] = pathinfo

        if result.type == 'exception':
            pathinfo['exception'] = '\n'.join(
                traceback.format_exception_only(*result.exc_info[:2]))
            self.nerror += 1
            return

        pathinfo['diverge'] = ', '.join(map(str, result.value.diverge))

        # Filter out non-commutative results
        if len(result.value.diverge):
            return

        if not self.trace_file and not self.testgen:
            return

        if self.trace_file:
            print >> self.trace_file, "=== Path %s ===" % result.pathid
            print >> self.trace_file

        e = result.path_condition

        ## This can potentially reduce the number of test cases
        ## by, e.g., eliminating irrelevant variables from e.
        ## The effect doesn't seem significant: one version of Fs
        ## produces 3204 test cases without simplify, and 3182 with.
        e = simsym.simplify(e)

        if args.verbose_testgen:
            print "Simplified path condition:"
            print e

        if self.trace_file:
            print >> self.trace_file, e
            print >> self.trace_file

        # Find the uninterpreted constants in the path condition.  We
        # omit assumptions because uninterpreted constants that appear
        # only in assumptions generally don't represent that the model
        # actually "touched".  We use the simplified expression
        # because the final state comparison in original expression
        # contains a lot of trivial expressions like x==x for all
        # state variables x, and we don't care about these
        # uninterpreted constants.
        e_vars = expr_vars(
            simsym.simplify(
                simsym.symand(
                    result.get_path_condition_list(
                        with_assume=False, with_det=True))))

        if self.testgen:
            self.testgen.begin_path(result)

        self.model_data_testinfo_list = []
        pathinfo['tests'] = self.model_data_testinfo_list

        self.npathmodel = 0
        self.last_assignments = None
        while not self.stop_call_set() and \
              self.npathmodel < args.max_tests_per_path:
            # XXX Would it be faster to reuse the solver?
            check = simsym.check(e)
            if check.is_sat and 'array-ext' in check.z3_model.sexpr():
                # Work around some non-deterministic bug that causes
                # Z3 to occasionally produce models containing
                # 'array-ext' applications that break evaluation.
                print 'Warning: Working around array-ext bug'
                for i in range(10):
                    check = simsym.check(e)
                    if not check.is_sat:
                        continue
                    if 'array-ext' not in check.z3_model.sexpr():
                        break
                else:
                    self._testerror('array-ext workaround failed', pathinfo)
                    break

            if check.is_unsat: break
            if check.is_unknown:
                # raise Exception('Cannot enumerate: %s' % str(e))
                self._testerror(check.reason, pathinfo)
                break

            if args.verbose_testgen:
                print "Model:"
                print check.model

            testid = ('_'.join(self.callset_names) +
                      '_' + result.pathid + '_' + str(self.npathmodel))
            testinfo = collections.OrderedDict(id=testid)
            self.model_data_testinfo_list.append(testinfo)

            assignments = self.__on_model(result, check.z3_model, e, testid)
            if assignments is None:
                break
            if args.verbose_testgen:
                print 'Assignments:'
                pprint.pprint(assignments)
            if args.diff_testgen:
                new_assignments = {}
                if self.last_assignments is not None:
                    for aexpr, val in assignments:
                        hexpr = z3util.HashableAst(aexpr)
                        sval = str(val)
                        last_sval = self.last_assignments.get(hexpr)
                        if last_sval is not None and last_sval != sval:
                            print '%s: %s -> %s' % (aexpr, last_sval, sval)
                        new_assignments[hexpr] = sval
                self.last_assignments = new_assignments

            testinfo['assignments'] = {}
            for aexpr, val in assignments[None]:
                testinfo['assignments'][str(aexpr)] = str(val)

            # Construct the isomorphism condition for the assignments
            # used by testgen.  This tells us exactly what values
            # actually mattered to test case generation.  However,
            # this set isn't perfect: testgen may have queried
            # assignments that didn't actually matter to the
            # function's behavior (e.g., flags that didn't matter
            # because the function will return an error anyway, etc).
            # To filter out such uninterpreted constants, we only
            # consider those that were *both* used in an assignment by
            # testgen and appeared in the path condition expression.
            # XXX We should revisit this and see how much difference
            # this makes.
            same = IsomorphicMatch()
            for realm, rassigns in assignments.iteritems():
                for aexpr, val in rassigns:
                    aexpr_vars = expr_vars(aexpr)
                    if not aexpr_vars.isdisjoint(e_vars):
                        same.add(realm, aexpr, val, result)
                    elif args.verbose_testgen:
                        print 'Ignoring assignment:', (aexpr, val)
            isocond = same.condition()

            # Compute idempotent projections for this test
            if args.idempotent_projs:
                projs, proj_errors = idempotent_projs(result, isocond)
                testinfo['idempotent_projs'] = projs
                if proj_errors:
                    testinfo['idempotence_unknown'] = proj_errors

            # Construct constraint for next test
            notsame = simsym.symnot(isocond)
            if args.verbose_testgen:
                print 'Negation', self.nmodel, ':', notsame
            e = simsym.symand([e, notsame])

        if self.npathmodel == args.max_tests_per_path:
            print '  Max tests reached for path %s' % result.pathid

        if self.testgen:
            self.testgen.end_path()
Example #28
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}
Example #29
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,
        )
Example #30
0
  def setup_proc(self, pid, fdmap, vamap, pipe_end_fds):
    emit = self.emit
    emit('int fd __attribute__((unused));',
         'int r __attribute__((unused));')
    for fd, (symfd, inode) in fdmap.items():
      if symfd.ispipe:
        pipe_setup_fd = self.pipes[symfd.pipeid]
        if symfd.pipewriter: pipe_setup_fd += 1
        emit('r = dup2(%d, %d);' % (pipe_setup_fd, fd),
             'if (r < 0) setup_error("dup2");')
      else:
        emit('fd = open("%s", O_RDWR);' % self.inums[symfd.inum].fname,
             'if (fd < 0) setup_error("open");',
             'r = lseek(fd, %d, SEEK_SET);' % (inode.offsets[symfd.off]),
             'if (fd >= 0 && r < 0) setup_error("lseek");',
             'r = dup2(fd, %d);' % fd,
             'if (fd >= 0 && r < 0) setup_error("dup2");',
             'close(fd);')

    # There may be other FDs open to pipes that never came up in the
    # test, but that matter to keep the pipe open.  Check for this
    # possibility for every pipe end.
    for (_, pipewriter), (pipeid, pidcounts) in pipe_end_fds.items():
      # How many of this end are already set up in this process?
      knowncount = pidcounts[pid]
      # Try to find > knowncount distinct instances of this end in
      # this process.
      conds = []
      distinct = []
      sym_fd_map = self.fs.getproc(pid).fd_map
      for i in range(knowncount + 1):
        ofdnum = fs_module.SFdNum.var()
        ofd = sym_fd_map._map[ofdnum]
        conds.extend([sym_fd_map._valid[ofdnum], ofd.ispipe,
                      ofd.pipeid == pipeid, ofd.pipewriter == pipewriter])
        distinct.append(ofdnum)
      if len(distinct) > 1:
        conds.append(simsym.distinct(*distinct))

      # XXX I've tried to *prove* that the path condition implies
      # there *must* be more FDs for this pipe end, so the decision
      # will stand regardless of choices made by model completion, but
      # I just can't get it to work:
      #  prove(simsym.implies(self.constraint,
      #                       simsym.exists(ofdnums, simsym.symand(conds))))

      result = simsym.check(simsym.symand([self.constraint] + conds))
      if result.is_unknown:
        print 'Warning: Unable to check pipe FD existence:', result.reason
      elif result.is_sat:
        # Open up another pipe end
        pipe_setup_fd = self.pipes[pipeid]
        if pipewriter: pipe_setup_fd += 1
        emit('r = dup(%d);' % pipe_setup_fd,
             'if (r < 0) setup_error("dup");')

    for va, vainfo in vamap.items():
      if vainfo.anon:
        emit('init_map_anon(%#x, %d, %d);' %
             (va, vainfo.writable.val,
              self.datavals[vainfo.anondata].first_byte))
      else:
        inode = self.inums[vainfo.inum]
        emit('init_map_file(%#x, %d, "%s", %#x);' %
             (va, vainfo.writable.val, inode.fname, inode.offsets[vainfo.off]))
 def _declare_assumptions(self, assume):
     super(ProcessQueue, self)._declare_assumptions(assume)
     # 'iseq' restriction
     i = simsym.SInt.var()
     j = simsym.SInt.var()
     assume(simsym.symnot(simsym.exists(i, simsym.exists(j, simsym.symand(i != j, i >= 0, j >= 0, i < self.elts.len(), j < self.elts.len(), self.elts[i] == self.elts[j])))))
Example #32
0
    def on_path(self, result):
        super(TestWriter, self).on_path(result)

        pathinfo = collections.OrderedDict([
            ('id', '_'.join(self.callset_names) + '_' + result.pathid)
        ])
        self.model_data_callset[result.pathid] = pathinfo

        if result.type == 'exception':
            pathinfo['exception'] = '\n'.join(
                traceback.format_exception_only(*result.exc_info[:2]))
            self.nerror += 1
            return

        pathinfo['diverge'] = ', '.join(map(str, result.value.diverge))

        # Filter out non-commutative results
        if len(result.value.diverge):
            return

        if not self.trace_file and not self.testgen:
            return

        if self.trace_file:
            print >> self.trace_file, "=== Path %s ===" % result.pathid
            print >> self.trace_file

        e = result.path_condition

        ## This can potentially reduce the number of test cases
        ## by, e.g., eliminating irrelevant variables from e.
        ## The effect doesn't seem significant: one version of Fs
        ## produces 3204 test cases without simplify, and 3182 with.
        e = simsym.simplify(e)

        if args.verbose_testgen:
            print "Simplified path condition:"
            print e

        if self.trace_file:
            print >> self.trace_file, e
            print >> self.trace_file

        # Find the uninterpreted constants in the path condition.  We
        # omit assumptions because uninterpreted constants that appear
        # only in assumptions generally don't represent that the model
        # actually "touched".  We use the simplified expression
        # because the final state comparison in original expression
        # contains a lot of trivial expressions like x==x for all
        # state variables x, and we don't care about these
        # uninterpreted constants.
        e_vars = expr_vars(
            simsym.simplify(
                simsym.symand(
                    result.get_path_condition_list(with_assume=False,
                                                   with_det=True))))

        if self.testgen:
            self.testgen.begin_path(result)

        self.model_data_testinfo_list = []
        pathinfo['tests'] = self.model_data_testinfo_list

        self.npathmodel = 0
        self.last_assignments = None
        while not self.stop_call_set() and \
              self.npathmodel < args.max_tests_per_path:
            # XXX Would it be faster to reuse the solver?
            check = simsym.check(e)
            if check.is_sat and 'array-ext' in check.z3_model.sexpr():
                # Work around some non-deterministic bug that causes
                # Z3 to occasionally produce models containing
                # 'array-ext' applications that break evaluation.
                print 'Warning: Working around array-ext bug'
                for i in range(10):
                    check = simsym.check(e)
                    if not check.is_sat:
                        continue
                    if 'array-ext' not in check.z3_model.sexpr():
                        break
                else:
                    self._testerror('array-ext workaround failed', pathinfo)
                    break

            if check.is_unsat: break
            if check.is_unknown:
                # raise Exception('Cannot enumerate: %s' % str(e))
                self._testerror(check.reason, pathinfo)
                break

            if args.verbose_testgen:
                print "Model:"
                print check.model

            testid = ('_'.join(self.callset_names) + '_' + result.pathid +
                      '_' + str(self.npathmodel))
            testinfo = collections.OrderedDict(id=testid)
            self.model_data_testinfo_list.append(testinfo)

            assignments = self.__on_model(result, check.z3_model, e, testid)
            if assignments is None:
                break
            if args.verbose_testgen:
                print 'Assignments:'
                pprint.pprint(assignments)
            if args.diff_testgen:
                new_assignments = {}
                if self.last_assignments is not None:
                    for aexpr, val in assignments:
                        hexpr = z3util.HashableAst(aexpr)
                        sval = str(val)
                        last_sval = self.last_assignments.get(hexpr)
                        if last_sval is not None and last_sval != sval:
                            print '%s: %s -> %s' % (aexpr, last_sval, sval)
                        new_assignments[hexpr] = sval
                self.last_assignments = new_assignments

            testinfo['assignments'] = {}
            for aexpr, val in assignments[None]:
                testinfo['assignments'][str(aexpr)] = str(val)

            # Construct the isomorphism condition for the assignments
            # used by testgen.  This tells us exactly what values
            # actually mattered to test case generation.  However,
            # this set isn't perfect: testgen may have queried
            # assignments that didn't actually matter to the
            # function's behavior (e.g., flags that didn't matter
            # because the function will return an error anyway, etc).
            # To filter out such uninterpreted constants, we only
            # consider those that were *both* used in an assignment by
            # testgen and appeared in the path condition expression.
            # XXX We should revisit this and see how much difference
            # this makes.
            same = IsomorphicMatch()
            for realm, rassigns in assignments.iteritems():
                for aexpr, val in rassigns:
                    aexpr_vars = expr_vars(aexpr)
                    if not aexpr_vars.isdisjoint(e_vars):
                        same.add(realm, aexpr, val, result)
                    elif args.verbose_testgen:
                        print 'Ignoring assignment:', (aexpr, val)
            isocond = same.condition()

            # Compute idempotent projections for this test
            if args.idempotent_projs:
                projs, proj_errors = idempotent_projs(result, isocond)
                testinfo['idempotent_projs'] = projs
                if proj_errors:
                    testinfo['idempotence_unknown'] = proj_errors

            # Construct constraint for next test
            notsame = simsym.symnot(isocond)
            if args.verbose_testgen:
                print 'Negation', self.nmodel, ':', notsame
            e = simsym.symand([e, notsame])

        if self.npathmodel == args.max_tests_per_path:
            print '  Max tests reached for path %s' % result.pathid

        if self.testgen:
            self.testgen.end_path()
Example #33
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])])