Esempio n. 1
0
def getTypedZ3ValFromIdentifier(identifier, types):
    if type(identifier) == dict:
        # FIXME how can we handle this here
        raise NotSupportedException('Complex objects as base for operations cannot be modelled in z3')
    if type(identifier) == list:
        arr = z3.Array('ignore_helper_constant_array_' + randomString(), z3.IntSort(), z3.StringSort())
        for i, arg in enumerate(identifier):
            GLOBAL_CONSTRAINTS.append(z3.Select(arr, i) == createZ3ExpressionFromConstraint(arg, types))
        ARRAY_LENGTHS[str(arr.decl())] = len(identifier)
        return arr

    cur_types = types
    GLOBAL_IDENTIFIER.add(identifier)
    cur_types = infered_types[identifier]
    # if cur_types == 'object':
    #    infered_types[identifier] = ''
    #    cur_types = ''
    if identifier.endswith('.length'):
        return z3.Length(z3.String(identifier[:-7]))

    if cur_types == 'string':
        return z3.String(identifier)
    elif cur_types == 'number':
        return z3.Int(identifier)
    elif cur_types == 'boolean':
        return z3.Bool(identifier)
    elif cur_types == 'array':
        return z3.Array(identifier, z3.IntSort(), z3.StringSort())

    if 'event.data' in identifier or 'event.origin' in identifier or 'event' == identifier:
        return z3.String(identifier)
    else:
        MAKE_UNSOLVABLE.add(identifier)
        return z3.String(identifier)
Esempio n. 2
0
def lenOfZ3(obj):
    if type(obj) == str or type(obj) == list:
        return len(obj)

    if z3.is_string(obj):
        return z3.Length(obj)

    raise Exception('Need to calculate length of unknown object')
Esempio n. 3
0
    def s_add_transition_to(self, w):
        """
        @pre len(w)>0
        """
        i = self.gennum()
        pre = Sequence("pre%d" % i)
        a = Sequence("a%d" % i)

        self.s.add(z3.Length(a) == 1)
        self.s.add(z3.Concat(pre, a) == self.stackvars[w[:-1]])
        x = self.d(a, z3.StringVal(w[-1:]))

        self.s.add(z3.Length(x) <= self.limitL)
        for i in range(self.limitL):
            self.s.add(
                z3.Implies(
                    z3.Length(x) > i,
                    z3.And(x[i] < z3.IntVal(self.limitS), x[i] >= 0)))

        self.s.add(z3.Concat(pre, x) == self.stackvars[w])
Esempio n. 4
0
def add_regex_constraints(solver, regex, max_length=None, symbolic=False) -> Dict[int, List[str]]:
    if max_length is None:
        # TODO: get max length from parsed regex.
        max_length = len(regex) + 15

    # WILDCARD_MARKER is not a valid URL char. Note that wildcards match ':' and '/'
    rs = RegexStringExpr(regex, unknown_string, dot_charset=WILDCARD_MARKER, symbolic=symbolic)
    expr = rs.re_expr()
    solver.add(expr)

    solver.add(z3.Length(unknown_string) <= max_length)
    return rs.symbols
Esempio n. 5
0
def string_split(x, args):
    st = x
    split_val = z3.StringVal(args[0].encode())
    x = transformNonBooleanLazyEvaluations(x)
    arr = z3.Array('__ignore_{}.split({})'.format(str(x), str(args[0])), z3.IntSort(), z3.StringSort())
    for i in range(3):
        index = z3.IndexOf(st, split_val, 0)
        s = z3.SubString(st, 0, index)
        st = z3.SubString(st, index + z3.Length(split_val), z3.Length(st))
        GLOBAL_CONSTRAINTS.append(z3.Select(arr, i) == s)
        GLOBAL_CONSTRAINTS.append(s != z3.StringVal(''))
        GLOBAL_ARRAY_HANDLER[arr].append(s)
    GLOBAL_CONSTRAINTS.append(z3.Select(arr, 3) == st)
    GLOBAL_CONSTRAINTS.append(st != z3.StringVal(''))
    GLOBAL_ARRAY_HANDLER[arr].append(st)
    # We just guess the length here and hope that this works for the program
    ARRAY_LENGTHS[str(arr.decl())] = 4

    GLOBAL_CONSTRAINTS.append(z3.IndexOf(GLOBAL_ARRAY_HANDLER[arr][-1], split_val, 0) == -1)
    # GLOBAL_CONSTRAINTS.append(z3.PrefixOf(GLOBAL_ARRAY_HANDLER[arr][0], x))

    return arr
Esempio n. 6
0
    def proc_apply(self, expr, state):
        f = self.context.reduce(expr['func'])
        args = expr['args']
        if f['what'] == 'expr:special':
            if f['id'] == 'gmap_lookup':
                state, k = self.proc(args[0], state)
                state, m = self.proc(args[1], state)
                return state, m[k]
            elif f['id'] == 'map_insert':
                state, k = self.proc(args[0], state)
                state, v = self.proc(args[1], state)
                state, m = self.proc(args[2], state)

                rangesort = m.range()
                vsome = constructor_by_name(rangesort, "Some")(v)

                return state, z3.Store(m, k, vsome)
            elif f['id'] == 'len_buf':
                state, buf = self.proc(args[0], state)
                return state, z3.Int2BV(z3.Length(buf), 64)
            elif f['id'] == 'resize_buf':
                state, newlen = self.proc(args[0], state)
                state, buf = self.proc(args[1], state)
                ## XXX should be of length newlen, not empty..
                return state, z3.Empty(buf.sort())
            elif f['id'] == 'uint64_gt':
                state, a0 = self.proc(args[0], state)
                state, a1 = self.proc(args[1], state)
                return state, z3.If(a0 > a1,
                                    self.bool_sort.constructor(0)(),
                                    self.bool_sort.constructor(1)())
            elif f['id'] == 'eqDec_time':
                state, a0 = self.proc(args[0], state)
                state, a1 = self.proc(args[1], state)
                return state, z3.If(a0 == a1,
                                    self.sumbool_sort.constructor(0)(),
                                    self.sumbool_sort.constructor(1)())
            else:
                raise Exception('unknown special function', f['id'])
        else:
            print expr
            raise Exception('unknown apply on', f['what'])
Esempio n. 7
0
def string_slice(x, args):
    if len(args) == 2:
        start = args[0]
        end = args[1]
    else:
        start = args[0]
        end = lenOfZ3(x)

    if type(start) != int:
        start = createZ3ExpressionFromConstraint(start, {})
    if type(end) != int and not z3.is_int(end):
        end = createZ3ExpressionFromConstraint(end, {})

    if type(start) == int and start < 0:
        GLOBAL_CONSTRAINTS.append(z3.Length(x) > -start)
        start = end + start

    if (z3.is_int(start) or type(start) == int) and (z3.is_int(start) or type(start) == int):
        return z3.SubString(x, start, end)
    else:
        raise NotSupportedException('')
Esempio n. 8
0
 def s_isFinalConfiguration(self, c):
     z3val = z3.StringVal(c)
     return z3.And(z3.Length(z3val) <= 1, self.Qf(z3val))
Esempio n. 9
0
 def s_isFinalWord(self, w):
     z3var = self.stackvars[w]
     return z3.And(z3.Length(z3var) <= 1, self.Qf(z3var))
Esempio n. 10
0
def SLength(text: SStr) -> z3.ArithRef:
    return z3.Length(text.expr)
Esempio n. 11
0
def init(s: z3.SeqRef) -> z3.SeqRef:
    ctx = s.ctx
    zero = z3.IntVal(0, ctx)
    one = z3.IntVal(1, ctx)
    return z3.SubString(s, zero, z3.Length(s) - one)
Esempio n. 12
0
def tail(s: z3.SeqRef) -> z3.SeqRef:
    ctx = s.ctx
    one = z3.IntVal(1, ctx)
    return z3.SubString(s, one, z3.Length(s))
Esempio n. 13
0
def last(s: z3.SeqRef) -> z3.SeqRef:
    ctx = s.ctx
    one = z3.IntVal(1, ctx)
    return s[z3.Length(s) - one]
Esempio n. 14
0
    def _sat_expr(
            self, regex: Tuple
    ) -> Tuple[z3.SeqRef, z3.BoolRef, z3.BoolRef, z3.BoolRef]:
        """

        :returns: string that matches regex, constraint on string,
             whether string contains caret, whether string contains dollar

        Whether there is a caret or dollar needs to be tracked because they imply constraints on
        neighboring strings to the one returned.

        """

        ty = regex[0]

        if ty == EMPTY:
            return (z3.StringVal(''), z3.BoolVal(True), z3.BoolVal(False),
                    z3.BoolVal(False))

        elif ty == CHAR:
            return (z3.StringVal(regex[1]), z3.BoolVal(True),
                    z3.BoolVal(False), z3.BoolVal(False))

        elif ty == DOT:
            x = self._gen_string_var()
            constraint = z3.And(
                z3.Implies(self.ignore_wildcards, x == z3.StringVal('')),
                z3.Implies(
                    z3.Not(self.ignore_wildcards),
                    z3.Or(*(x == z3.StringVal(y) for y in self.dot_charset))))
            return (x, constraint, z3.BoolVal(False), z3.BoolVal(False))

        elif ty == STAR:
            # STAR should have been approximated with something else during preprocessing.
            raise NotImplementedError

        elif ty == BAR:
            ys, constraints_list, carets_list, dollars_list = zip(
                *map(self._sat_expr, regex[1:]))

            x = self._gen_string_var()
            x_constraint = z3.Or(
                *(z3.And(x == y, y_constraint)
                  for y, y_constraint in zip(ys, constraints_list)))

            return (x, x_constraint, z3.Or(*carets_list), z3.Or(*dollars_list))
        elif ty == CONCAT:

            ys, y_constraints, carets_list, dollars_list = zip(
                *map(self._sat_expr, regex[1:]))

            x = z3.Concat(*ys)

            start_constraints = (z3.Implies(b,
                                            z3.Length(y) == 0)
                                 for ii, b in enumerate(carets_list)
                                 for y in ys[:ii])

            end_constraints = (z3.Implies(b,
                                          z3.Length(y) == 0)
                               for ii, b in enumerate(dollars_list)
                               for y in ys[ii + 1:])

            x_constraint = z3.And(*toolz.concatv(
                y_constraints, start_constraints, end_constraints))

            return (x, x_constraint, z3.Or(*carets_list), z3.Or(*dollars_list))

        elif ty == GROUP:
            # backrefs not supported
            idx = regex[
                1] - 1  # not used currently; would be used to implement backrefs
            inner = regex[2]
            return self._sat_expr(inner)

        elif ty == BACKREF:
            raise NotImplementedError

        elif ty == CARET:
            assert len(regex) == 1
            b = self._gen_bool_var()
            return (z3.StringVal(''), b, b, z3.BoolVal(False))

        elif ty == DOLLAR:
            assert len(regex) == 1
            b = self._gen_bool_var()
            return (z3.StringVal(''), b, z3.BoolVal(False), b)

        else:
            raise ValueError("Unknown regex_parser type '%s'" % repr(ty))
Esempio n. 15
0
 def __len__(self):
     debug('__len__ called ', self.z3var)
     return SymbolicInt(z3.Length(self.z3var))
Esempio n. 16
0
def generate_constraints(data):
    I = len(data[0]) # number of inflections
    
    count = 0
    cost_constraint = 0
    column_cost = [0]*I
    length_c = 0
    constraints = []
    for example in data:
        suffixes = [z3.String('suf' + chr(ord('A') + i))
                    for i in range(I) ]
        prefixes = [z3.String('pre' + chr(ord('A') + i))
                    for i in range(I) ]
        # preA = z3.String('preA')
        # preB = z3.String('preB')
        # sufA = z3.String('sufA')
        # sufB = z3.String('sufB')
        stem = z3.String('stem' + str(count))

        # 1 is associated with the prefix
        unch1 = [z3.String('unch1' + str(count) + chr(ord('A') + i))
                 for i in range(I) ]
        # 2 is associated with the suffix
        unch2 = [z3.String('unch2' + str(count) + chr(ord('A') + i))
                 for i in range(I) ]

        # unchA1 = z3.String('unch' + str(count) + 'A') 
        # unchA2 = z3.String('unch' + str(count) + 'B')

        # unchB1 = z3.String('unch' + str(count) + 'C')
        # unchB2 = z3.String('unch' + str(count) + 'D')

        ch = [z3.String('ch' + str(count) + chr(ord('A') + i))
              for i in range(I) ]

        var = [z3.String('var' + str(count) + chr(ord('A') + i))
              for i in range(I) ]
        # varA = z3.String('var' + str(count) + 'A')
        # varB = z3.String('var' + str(count) + 'B')

        # scA = z3.Int('sc'+str(count)+'A')
        # scB = z3.Int('sc'+str(count)+'B')
        sc = [z3.Int('sc' + str(count) + chr(ord('A') + i))
              for i in range(I) ]
        
        lc = z3.Int('l'+str(count))
        for v in var:
            constraints.append(z3.Length(v) <= 1)
        # constraints.append(z3.Length(varA) <= 1)
        # constraints.append(z3.Length(varB) <= 1)
        for i in range(I):
            constraints.append(z3.Concat(prefixes[i],stem,suffixes[i]) == z3.Concat(unch1[i],ch[i],unch2[i]))
        # constraints.append(z3.Concat(preA,stem,sufA) == z3.Concat(unchA1,chA,unchA2))
        # constraints.append(z3.Concat(preB,stem,sufB) == z3.Concat(unchB1,chB,unchB2))
        for i in range(I):
            if len(example[i]) == 0: continue
            constraints.append(z3.StringVal(convert_ipa(example[i],m)) == z3.Concat(unch1[i],var[i],unch2[i]))
            
        # constraints.append(z3.StringVal(convert_ipa(example[0],m)) == z3.Concat(unchA1,varA,unchA2))
        # constraints.append(z3.StringVal(convert_ipa(example[1],m)) == z3.Concat(unchB1,varB,unchB2))
        
        constraints.append(z3.Length(stem) == lc)

        for i in range(I):
            constraints.append(z3.If(ch[i] == var[i],0,1) == sc[i])
            
        #constraints.append(z3.If(chB == varB,0,1) == scB)
        
        length_c = length_c + lc

        for i in range(I):
            constraints.append(sc[i] <= 1)
        cost_constraint = cost_constraint + sum(sc)
        for i in range(I):
            column_cost[i] = column_cost[i] + sc[i]
        count += 1
    return constraints, cost_constraint, column_cost
Esempio n. 17
0
def wildcard_trace(solver, symbols: Dict[int, List[str]], use_priming=True) -> Tuple[z3.CheckSatResult, Dict]:
    """Return the result of the attack (sat means attack was successful) and associated data.

    If the attack was successful, associated data includes what attack was executed, witness
    information, and the solution found.  The dictionary keys are "strategy", "solution", "witness".

    Otherwise, associated data includes the attack that was executed, plus debug info under the key
    "debug_info".

    """

    if use_priming:
        # prime the solver with an easy question.
        # In `test_optional_dollar` it seems to give several folds speedup, if you used the same
        # solver for `test_dot` previously.
        prime_result, prime_model = check_formulae(solver, z3.Not(RegexStringExpr.ignore_wildcards))
        logger.info('check %s', prime_result)
        if prime_result == z3.sat:
            logger.debug(public_vars(prime_model))
        else:
            solver.reset()
            return prime_result, None

    base = proto + proto_delimiter + fqdn

    solver.add(
        z3.Or(proto_delimiter == z3.StringVal('//'), proto_delimiter == z3.StringVal(WILDCARD_MARKER * 2)),
        z3.Xor(z3.PrefixOf(base + '/', unknown_string), base == unknown_string),
        z3.Not(z3.Contains(proto, '/')),
        z3.Not(z3.Contains(fqdn, '/')),
        z3.Length(proto) > 0,
        z3.Length(fqdn) > 0,
        )

    if DEBUG:
        #debug_result, debug_model = check_formulae(solver, unknown_string == debug_model[unknown_string])
        #logger.debug(debug_model)

        debug_result = solver.check()
        logger.debug(debug_result)
        if debug_result == z3.sat:
            debug_model = solver.model()
            logger.debug(public_vars(debug_model))
            ans = z3.simplify(debug_model[proto] + debug_model[proto_delimiter] + debug_model[fqdn])
        else:
            return debug_result, None


        #debug_result, debug_model = check_formulae(solver, (base_url != ans))

    result, model = check_formulae(solver,
                                   z3.Not(RegexStringExpr.ignore_wildcards),
                                   z3.Contains(proto + fqdn, z3.StringVal(WILDCARD_MARKER)))

    if result == z3.sat:
        _conc1 = lambda zs: tz.first(concretizations(z3_str_to_bytes(zs), symbols))
        logger.info(public_vars(model))
        ans = z3.simplify(model[proto] + model[proto_delimiter] + model[fqdn])
        return result, {
            'solution': _conc1(model[unknown_string]).replace(WILDCARD_MARKER, OUTPUT_WILDCARD_MARKER),
            'strategy': 'wildcard_trace',
            'witness': _conc1(ans).replace(WILDCARD_MARKER, OUTPUT_WILDCARD_MARKER)}
    else:
        return result, {'strategy': 'wildcard_trace',
                        'debug_info': None}
Esempio n. 18
0
def createZ3ExpressionFromConstraint(constraint, types, emitParentConstraint=True):
    if type(constraint) != dict:
        if type(constraint) == str:
            return z3.StringVal(constraint)
        if type(constraint) == int:
            return z3.IntVal(constraint)
        if type(constraint) == bool:
            return z3.BoolVal(constraint)
        if constraint is None:
            return None
        raise Exception('Dealing with non-int non-string basic values, aborting!', constraint)
    if 'type' not in constraint:
        if 'isRealValue' in constraint:
            if 'value' in constraint:
                var = getZ3ValFromJSVal(constraint['value'])
            elif 'val' in constraint:
                var = getZ3ValFromJSVal(constraint['val'])
            else:
                raise Exception('Should not encounter realValue without reference to the real value...')
        else:
            if 'identifier' in constraint:
                var = getTypedZ3ValFromIdentifier(constraint['identifier'], types)
            else:
                # probably the empty object when we have something || {}
                return None

        for op in constraint['ops']:
            if 'val' not in op:
                op['val'] = ''
            if op['type'] == 'ops_on_parent_element':
                val = resolveOpsOnParent(op, types)
                if z3.is_array(val):
                    accesed = constraint['identifier'].split('.')[-1]
                    if accesed == 'length':
                        raise NotSupportedException(
                            'z3 cannot use the length of arrays due to their representation as functions')
                    if int(accesed) < 0 and str(val.decl()) in ARRAY_LENGTHS:
                        var = z3.Select(val, ARRAY_LENGTHS[str(val.decl())] + int(accesed))
                    else:
                        var = z3.Select(val, int(accesed))
                elif val is not None:
                    key = str(val)
                    if key not in identifier_substitutions:
                        identifier_substitutions[key] = '__substitute_values_' + randomString()
                    identifier = identifier_substitutions[key]
                    GLOBAL_CONSTRAINTS.append(val == z3.StringVal(identifier))
                    accesed = constraint['identifier'].split('.')[-1]
                    if accesed == 'length':
                        var = z3.Length(z3.String(identifier))
                    else:
                        var = z3.String(identifier + '.' + accesed)

                #     GLOBAL_CONSTRAINTS.append(var == val)
            elif op['type'] == 'member_function':
                var = transformNonBooleanLazyEvaluations(var)
                if op['function_name'] in StringFunctions:
                    var = StringFunctions[op['function_name']](var, op['args'])
                elif op['function_name'] in ArrayFunctions:
                    var = ArrayFunctions[op['function_name']](var, op['args'])
                else:
                    if op['function_name'] in ['call', 'apply', 'bind']:
                        raise NotSupportedException('We do not support function calls over function pointer')
                    raise Exception('String function not supported! ' + op['function_name'])
            elif op['type'] == 'Binary':
                other_var = createZ3ExpressionFromConstraint(op['val'], types)
                if other_var is None:
                    # this is the case when we compare something to null
                    if op['op'] == '===' or op['op'] == '==':
                        var = createZ3ForBool(var)
                        var = z3.Not(var)
                    continue
                var, other_var = coerceTypesIfPossible(var, other_var)
                changed = checkForTypeEqualToString(var, other_var, op)
                if changed is not None:
                    var = changed
                elif op['side'] == 'left':
                    var = BinaryFunctions[op['op']](var, other_var)
                elif op['side'] == 'right':
                    var = BinaryFunctions[op['op']](other_var, var)
                else:
                    var = BinaryFunctions[op['op']](var, other_var)
            elif op['type'] == 'Unary':
                var = UnaryFunctions[op['op']](var)
            elif op['type'] == 'iterator':
                if z3.is_array(var):
                    var = z3.Select(var, op['accessed_elem'])
                else:
                    raise Exception('This should always be an array', var, infered_types)
            elif op['type'] == 'external_function':
                if op['function_name'] == 'JSON.parse':
                    infered_types[constraint['identifier']] = 'JSON'
                    var = z3.String(constraint['identifier'])
                else:
                    logging.debug('Arbitrary external functions not yet support ' + op['function_name'])
            elif op['type'] == 'Logical':
                if op['side'] == 'left' or op['side'] == 'both':
                    l_c = createZ3ForBool(var)
                    r_c = createZ3ForBool(createZ3ExpressionFromConstraint(op['val'], types))
                else:
                    l_c = createZ3ForBool(createZ3ExpressionFromConstraint(op['val'], types))
                    r_c = createZ3ForBool(var)
                if l_c is None or r_c is None:
                    if l_c is None:
                        var = r_c
                    if r_c is None:
                        var = l_c
                    continue
                if op['op'] == '&&':
                    var = z3.And(l_c, r_c)
                else:
                    var = z3.Or(l_c, r_c)
            else:
                logging.debug('Not supported type ' + op['type'])
        return var
    elif constraint['type'] == 'Logical':
        l_c = createZ3ForBool(createZ3ExpressionFromConstraint(constraint['l_val'], types))
        r_c = createZ3ForBool(createZ3ExpressionFromConstraint(constraint['r_val'], types))
        if l_c is None or r_c is None:
            return l_c or r_c
        if constraint['op'] == '&&':
            return z3.And(l_c, r_c)
        else:
            return z3.Or(l_c, r_c)
    elif constraint['type'] == 'Binary':
        return BinaryFunctions[constraint['op']](createZ3ExpressionFromConstraint(constraint['l_val'], types),
                                                 createZ3ExpressionFromConstraint(constraint['r_val'], types))
    elif constraint['type'] == 'Unary':
        return UnaryFunctions[constraint['op']](createZ3ExpressionFromConstraint(constraint['val'], types))
    else:
        raise Exception('Unexpected constraint type')
Esempio n. 19
0
def z3_str_to_bytes(zs: z3.StringVal):
    ll = z3.simplify(z3.Length(zs)).as_long()
    return bytes([z3_byte_to_ord[z3.simplify(zs[ii])] for ii in range(ll)])
Esempio n. 20
0
 def s_add_nonemptystate(self, w):
     z3var = self.stackvars[w]
     self.s.add(z3.Not(z3.Length(z3var) == 0))
Esempio n. 21
0
def _internal_match_patterns(space: StateSpace, top_patterns: Any, flags: int,
                             smtstr: z3.ExprRef,
                             offset: int) -> Optional[_Match]:
    """
    >>> from crosshair.statespace import SimpleStateSpace
    >>> import sre_parse
    >>> smtstr = z3.String('smtstr')
    >>> space = SimpleStateSpace()
    >>> space.add(smtstr == z3.StringVal('aabb'))
    >>> _internal_match_patterns(space, sre_parse.parse('a+'), 0, smtstr, 0).span()
    (0, 2)
    >>> _internal_match_patterns(space, sre_parse.parse('ab'), 0, smtstr, 1).span()
    (1, 3)
    """
    matchstr = z3.SubString(smtstr, offset,
                            z3.Length(smtstr)) if offset > 0 else smtstr
    if len(top_patterns) == 0:
        return _Match([(None, offset, offset)])
    pattern = top_patterns[0]

    def continue_matching(prefix):
        suffix = _internal_match_patterns(space, top_patterns[1:], flags,
                                          smtstr, prefix.end())
        if suffix is None:
            return None
        return prefix._add_match(suffix)

    # TODO: using a typed internal function triggers __hash__es inside the typing module.
    # Seems like this casues nondeterminism due to a global LRU cache used by the typing module.
    def fork_on(expr, sz):
        if space.smt_fork(expr):
            return continue_matching(_Match([(None, offset, offset + sz)]))
        else:
            return None

    # Handle simple single-character expressions using z3's built-in capabilities.
    z3_re = single_char_regex(pattern, flags)
    if z3_re is not None:
        ch = z3.SubString(matchstr, 0, 1)
        return fork_on(z3.InRe(ch, z3_re), 1)

    (op, arg) = pattern
    if op is MAX_REPEAT:
        (min_repeat, max_repeat, subpattern) = arg
        if max_repeat < min_repeat:
            return None
        reps = 0
        overall_match = _Match([(None, offset, offset)])
        while reps < min_repeat:
            submatch = _internal_match_patterns(space, subpattern, flags,
                                                smtstr, overall_match.end())
            if submatch is None:
                return None
            overall_match = overall_match._add_match(submatch)
            reps += 1
        if max_repeat != MAXREPEAT and reps >= max_repeat:
            return continue_matching(overall_match)
        submatch = _internal_match_patterns(space, subpattern, flags, smtstr,
                                            overall_match.end())
        if submatch is None:
            return continue_matching(overall_match)
        # we matched; try to be greedy first, and fall back to `submatch` as the last consumed match
        greedy_remainder = _patt_replace(
            top_patterns,
            arg,
            (
                1,
                max_repeat if max_repeat == MAXREPEAT else max_repeat -
                (min_repeat + 1),
                subpattern,
            ),
        )
        greedy_match = _internal_match_patterns(space, greedy_remainder, flags,
                                                smtstr, submatch.end())
        if greedy_match is not None:
            return overall_match._add_match(submatch)._add_match(greedy_match)
        else:
            match_with_optional = continue_matching(
                overall_match._add_match(submatch))
            if match_with_optional is not None:
                return match_with_optional
            else:
                return continue_matching(overall_match)
    elif op is BRANCH and arg[0] is None:
        # NOTE: order matters - earlier branches are more greedily matched than later branches.
        branches = arg[1]
        first_path = list(branches[0]) + list(top_patterns)[1:]
        submatch = _internal_match_patterns(space, first_path, flags, smtstr,
                                            offset)
        # _patt_replace(top_patterns, pattern, branches[0])
        if submatch is not None:
            return submatch
        if len(branches) <= 1:
            return None
        else:
            return _internal_match_patterns(
                space,
                _patt_replace(top_patterns, branches, branches[1:]),
                flags,
                smtstr,
                offset,
            )
    elif op is AT:
        if arg in (AT_END, AT_END_STRING):
            if arg is AT_END and re.MULTILINE & flags:
                raise ReUnhandled("Multiline match with AT_END_STRING")
            return fork_on(matchstr == z3.StringVal(""), 0)
    elif op is SUBPATTERN:
        (groupnum, _a, _b, subpatterns) = arg
        if (_a, _b) != (0, 0):
            raise ReUnhandled("unsupported subpattern args")
        new_top = (list(subpatterns) + [(_END_GROUP_MARKER,
                                         (groupnum, offset))] +
                   list(top_patterns)[1:])
        return _internal_match_patterns(space, new_top, flags, smtstr, offset)
    elif op is _END_GROUP_MARKER:
        (group_num, begin) = arg
        match = continue_matching(_Match([(None, offset, offset)]))
        if match is None:
            return None
        while len(match._groups) <= group_num:
            match._groups.append(None)
        match._groups[group_num] = (None, begin, offset)
        return match
    raise ReUnhandled(op)
Esempio n. 22
0
    def proc_apply(self, expr, state):
        f = self.context.reduce(expr['func'])
        args = expr['args']

        if f['what'] == 'expr:special':
            # for converting Z to u32
            if f['id'] == 'u3' or f['id'] == 'u2':
                arg = args[0]
                # be able to distinguish between Z->u32 and Z->u64
                if f['id'] == 'u3':
                    arg['name'] = 'u32'
                else:
                    arg['name'] = 'u64'
                state, val = self.proc(arg, state)
                return state, z3.Const(anon(), val)

            elif f['id'] == 'gtb':
                arg0 = args[0]['cases'][0]['body']['args'][0]
                nstate, arg1 = self.proc(
                    args[1]['cases'][0]['body']['args'][0], state)
                return nstate, z3.If(arg0 > arg1,
                                     self.bool_sort.constructor(0)(),
                                     self.bool_sort.constructor(1)())

            elif f['id'] == 'gmap_lookup':
                state, k = self.proc(args[0], state)
                state, m = self.proc(args[1], state)
                return state, m[k]

            elif f['id'] == 'map_insert':
                state, k = self.proc(args[0], state)
                state, v = self.proc(args[1], state)
                state, m = self.proc(args[2], state)

                rangesort = m.range()
                vsome = constructor_by_name(rangesort, "Some")(v)

                return state, z3.Store(m, k, vsome)

            elif f['id'] == 'reads':
                return state, state

            elif f['id'] == 'modify':
                _, newstate = self.proc(args[0]['body'], state)
                return newstate, self.unit_tt

            elif f['id'] == 'ret':
                state, res = self.proc(args[0], state)
                return state, res

            elif f['id'] == 'len_buf':
                state, buf = self.proc(args[0], state)
                return state, z3.Int2BV(z3.Length(buf), 64)

            elif f['id'] == 'resize_buf':
                state, newlen = self.proc(args[0], state)
                state, buf = self.proc(args[1], state)
                ## XXX should be of length newlen, not empty..
                return state, z3.Empty(buf.sort())

            elif f['id'] == 'eqDec_time':
                state, a0 = self.proc(args[0], state)
                state, a1 = self.proc(args[1], state)
                return state, z3.If(a0 == a1,
                                    self.sumbool_sort.constructor(0)(),
                                    self.sumbool_sort.constructor(1)())

            elif f['id'] == 'time_ge':
                state, a0 = self.proc(args[0], state)
                state, a1 = self.proc(args[1], state)
                # constructor 0 is true, 1 is false
                return state, z3.If(a0 >= a1,
                                    self.bool_sort.constructor(0)(),
                                    self.bool_sort.constructor(1)())

            elif f['id'] == 'symAssert':
                state, a = self.proc(args[0], state)
                return state, z3.And(a == self.bool_sort.constructor(0)())

            else:
                raise Exception('unknown special function', f['id'])
        else:
            raise Exception('unknown apply on', f['what'])
Esempio n. 23
0
def generate_constraints(data):
    inflections = len(data[0])
    count = 0
    cost_constraint = 0
    cc = [0] * inflections

    constraints = []
    for example in data:
        suffixes = [
            z3.String('suf' + chr(ord('A') + i)) for i in range(inflections)
        ]
        prefixes = [
            z3.String('pre' + chr(ord('A') + i)) for i in range(inflections)
        ]

        stemA = z3.String('stem' + str(count) + 'A')

        variables = [
            z3.String('var' + str(count) + chr(ord('A') + i))
            for i in range(inflections)
        ]

        pvariables = [
            z3.String('pvar' + str(count) + chr(ord('A') + i))
            for i in range(inflections)
        ]

        pstemB = z3.String('pstem' + str(count) + 'B')
        stemB = z3.String('stem' + str(count) + 'B')

        sc = [
            z3.Int('sc' + str(count) + chr(ord('A') + i))
            for i in range(inflections)
        ]

        pc = [
            z3.Int('pc' + str(count) + chr(ord('A') + i))
            for i in range(inflections)
        ]

        for v in variables:
            constraints.append(z3.Length(v) <= 1)
        for v in pvariables:
            constraints.append(z3.Length(v) <= 1)
        for i in range(inflections):
            if len(example[i]) > 0:
                print(example[i], convert_ipa(example[i], m))
                constraints.append(
                    z3.StringVal(convert_ipa(example[i], m)) == z3.Concat(
                        prefixes[i], pvariables[i], stemA, variables[i],
                        suffixes[i]))

        for v in variables:
            constraints.append(z3.Length(stemB) == z3.Length(v))

        for v in pvariables:
            constraints.append(z3.Length(pstemB) == z3.Length(v))

        for i in range(inflections):
            constraints.append(z3.If(stemB == variables[i], 0, 1) == sc[i])

        for i in range(inflections):
            constraints.append(z3.If(pstemB == pvariables[i], 0, 1) == pc[i])

        for cost_variable in sc + pc:
            cost_constraint = cost_constraint + cost_variable

        count += 1
    return constraints, cost_constraint