[pypy-commit] pypy fix-sre-problems: fix issue 2777:
cfbolz
pypy.commits at gmail.com
Mon Mar 26 12:01:48 EDT 2018
Author: Carl Friedrich Bolz-Tereick <cfbolz at gmx.de>
Branch: fix-sre-problems
Changeset: r94135:b3264f1f3592
Date: 2018-03-26 18:01 +0200
http://bitbucket.org/pypy/pypy/changeset/b3264f1f3592/
Log: fix issue 2777:
before this commit, the following problem could occur: when the tags
of the opencoder overflow, it raises SwitchToBlackHole in the middle
of a jitcode opcode. Potentially, in the middle of a guard, *before*
the guard changed the pc on the MIFrame! That way, the blackhole
interpreter would continue in the wrong branch :-(.
Fix this by changing the interface slightly: opencoder.Trace.record
will now just not record anything, if the tags overflow. Instead, it
will set a flag on itself, which the metatracer needs to check after
every opcode, to find out whether to stop tracing.
diff --git a/rpython/jit/metainterp/history.py b/rpython/jit/metainterp/history.py
--- a/rpython/jit/metainterp/history.py
+++ b/rpython/jit/metainterp/history.py
@@ -701,6 +701,9 @@
def length(self):
return self.trace._count - len(self.trace.inputargs)
+ def trace_tag_overflow(self):
+ return self.trace.tag_overflow
+
def get_trace_position(self):
return self.trace.cut_point()
diff --git a/rpython/jit/metainterp/opencoder.py b/rpython/jit/metainterp/opencoder.py
--- a/rpython/jit/metainterp/opencoder.py
+++ b/rpython/jit/metainterp/opencoder.py
@@ -293,6 +293,7 @@
self._start = len(inputargs)
self._pos = self._start
self.inputargs = inputargs
+ self.tag_overflow = False
def append(self, v):
model = get_model(self)
@@ -300,7 +301,8 @@
# grow by 2X
self._ops = self._ops + [rffi.cast(model.STORAGE_TP, 0)] * len(self._ops)
if not model.MIN_VALUE <= v <= model.MAX_VALUE:
- raise frontend_tag_overflow()
+ v = 0 # broken value, but that's fine, tracing will stop soon
+ self.tag_overflow = True
self._ops[self._pos] = rffi.cast(model.STORAGE_TP, v)
self._pos += 1
@@ -379,6 +381,7 @@
def record_op(self, opnum, argboxes, descr=None):
pos = self._index
+ old_pos = self._pos
self.append(opnum)
expected_arity = oparity[opnum]
if expected_arity == -1:
@@ -397,6 +400,10 @@
self._count += 1
if opclasses[opnum].type != 'v':
self._index += 1
+ if self.tag_overflow:
+ # potentially a broken op is left behind
+ # clean it up
+ self._pos = old_pos
return pos
def _encode_descr(self, descr):
@@ -424,10 +431,11 @@
vref_array = self._list_of_boxes(vref_boxes)
s = TopSnapshot(combine_uint(jitcode.index, pc), array, vable_array,
vref_array)
- assert rffi.cast(lltype.Signed, self._ops[self._pos - 1]) == 0
# guards have no descr
self._snapshots.append(s)
- self._ops[self._pos - 1] = rffi.cast(get_model(self).STORAGE_TP, len(self._snapshots) - 1)
+ if not self.tag_overflow: # otherwise we're broken anyway
+ assert rffi.cast(lltype.Signed, self._ops[self._pos - 1]) == 0
+ self._ops[self._pos - 1] = rffi.cast(get_model(self).STORAGE_TP, len(self._snapshots) - 1)
return s
def create_empty_top_snapshot(self, vable_boxes, vref_boxes):
@@ -436,10 +444,11 @@
vref_array = self._list_of_boxes(vref_boxes)
s = TopSnapshot(combine_uint(2**16 - 1, 0), [], vable_array,
vref_array)
- assert rffi.cast(lltype.Signed, self._ops[self._pos - 1]) == 0
# guards have no descr
self._snapshots.append(s)
- self._ops[self._pos - 1] = rffi.cast(get_model(self).STORAGE_TP, len(self._snapshots) - 1)
+ if not self.tag_overflow: # otherwise we're broken anyway
+ assert rffi.cast(lltype.Signed, self._ops[self._pos - 1]) == 0
+ self._ops[self._pos - 1] = rffi.cast(get_model(self).STORAGE_TP, len(self._snapshots) - 1)
return s
def create_snapshot(self, jitcode, pc, frame, flag):
diff --git a/rpython/jit/metainterp/pyjitpl.py b/rpython/jit/metainterp/pyjitpl.py
--- a/rpython/jit/metainterp/pyjitpl.py
+++ b/rpython/jit/metainterp/pyjitpl.py
@@ -2384,7 +2384,8 @@
def blackhole_if_trace_too_long(self):
warmrunnerstate = self.jitdriver_sd.warmstate
- if self.history.length() > warmrunnerstate.trace_limit:
+ if (self.history.length() > warmrunnerstate.trace_limit or
+ self.history.trace_tag_overflow()):
jd_sd, greenkey_of_huge_function = self.find_biggest_function()
self.history.trace.done()
self.staticdata.stats.record_aborted(greenkey_of_huge_function)
diff --git a/rpython/jit/metainterp/test/test_ajit.py b/rpython/jit/metainterp/test/test_ajit.py
--- a/rpython/jit/metainterp/test/test_ajit.py
+++ b/rpython/jit/metainterp/test/test_ajit.py
@@ -4661,3 +4661,36 @@
f() # finishes
self.meta_interp(f, [])
+
+ def test_trace_too_long_bug(self):
+ driver = JitDriver(greens=[], reds=['i'])
+ @unroll_safe
+ def match(s):
+ l = len(s)
+ p = 0
+ for i in range(2500): # produces too long trace
+ c = s[p]
+ if c != 'a':
+ return False
+ p += 1
+ if p >= l:
+ return True
+ c = s[p]
+ if c != '\n':
+ p += 1
+ if p >= l:
+ return True
+ else:
+ return False
+ return True
+
+ def f(i):
+ while i > 0:
+ driver.jit_merge_point(i=i)
+ match('a' * (500 * i))
+ i -= 1
+ return i
+
+ res = self.meta_interp(f, [10])
+ assert res == f(10)
+
diff --git a/rpython/jit/metainterp/test/test_opencoder.py b/rpython/jit/metainterp/test/test_opencoder.py
--- a/rpython/jit/metainterp/test/test_opencoder.py
+++ b/rpython/jit/metainterp/test/test_opencoder.py
@@ -209,5 +209,8 @@
def test_tag_overflow(self):
t = Trace([], metainterp_sd)
i0 = FakeOp(100000)
- py.test.raises(SwitchToBlackhole, t.record_op, rop.FINISH, [i0])
- assert t.unpack() == ([], [])
+ # if we overflow, we can keep recording
+ for i in range(10):
+ t.record_op(rop.FINISH, [i0])
+ assert t.unpack() == ([], [])
+ assert t.tag_overflow
diff --git a/rpython/rlib/rsre/test/test_zjit.py b/rpython/rlib/rsre/test/test_zjit.py
--- a/rpython/rlib/rsre/test/test_zjit.py
+++ b/rpython/rlib/rsre/test/test_zjit.py
@@ -11,6 +11,8 @@
match = None
for i in range(repeat):
match = rsre_core.match(r, string)
+ if match is None:
+ return -1
if match is None:
return -1
else:
@@ -166,3 +168,9 @@
res = self.meta_interp_search(r"b+", "a"*30 + "b")
assert res == 30
self.check_resops(call=0)
+
+ def test_match_jit_bug(self):
+ pattern = ".a" * 2500
+ text = "a" * 6000
+ res = self.meta_interp_match(pattern, text, repeat=10)
+ assert res != -1
More information about the pypy-commit
mailing list