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)
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')
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])
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
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
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'])
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('')
def s_isFinalConfiguration(self, c): z3val = z3.StringVal(c) return z3.And(z3.Length(z3val) <= 1, self.Qf(z3val))
def s_isFinalWord(self, w): z3var = self.stackvars[w] return z3.And(z3.Length(z3var) <= 1, self.Qf(z3var))
def SLength(text: SStr) -> z3.ArithRef: return z3.Length(text.expr)
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)
def tail(s: z3.SeqRef) -> z3.SeqRef: ctx = s.ctx one = z3.IntVal(1, ctx) return z3.SubString(s, one, z3.Length(s))
def last(s: z3.SeqRef) -> z3.SeqRef: ctx = s.ctx one = z3.IntVal(1, ctx) return s[z3.Length(s) - one]
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))
def __len__(self): debug('__len__ called ', self.z3var) return SymbolicInt(z3.Length(self.z3var))
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
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}
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')
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)])
def s_add_nonemptystate(self, w): z3var = self.stackvars[w] self.s.add(z3.Not(z3.Length(z3var) == 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)
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'])
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