def string_substring(x, args): startIndex = createZ3ExpressionFromConstraint(args[0], {}) endIndex = lenOfZ3(x) if len(args) == 2: endIndex = createZ3ExpressionFromConstraint(args[1], {}) return z3.SubString(x, startIndex, endIndex)
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 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 SSubstr(text: SStr, offset: SInt, length: SInt) -> z3.SeqRef: return z3.SubString(text.expr, offset.expr, length.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 _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 _slice_match_area(string, pos=0, endpos=None): smtstr = string.var if endpos is not None: smtstr = z3.SubString(smtstr, 0, endpos) return smtstr
def _slice_tail(string: SymbolicStr, endpos: Optional[int] = None) -> SymbolicStr: smtstr = string.var if endpos is not None: smtstr = z3.SubString(smtstr, 0, endpos) return smtstr