fix segfault for wikimedia

If you call a static method on a instance, we decRef the object before running the method. If that is the last reference to the object, then its destructor will be called right in the middle of setting up the ActRec for the static method. Currently, the top of the stack will be off by 2 Cells because we have already popped off one Cell (the object) and an ActRec takes up 3 Cells.

Instead, we have to have the top of the stack to be after the ActRec that we are building for the next method call.
Esse commit está contido em:
Paul Tarjan
2013-05-12 12:25:16 -07:00
commit de Sara Golemon
commit b2de6fb9da
5 arquivos alterados com 55 adições e 1 exclusões
@@ -1771,6 +1771,11 @@ void HhbcTranslator::emitFPushObjMethodD(int32_t numParams,
nullptr);
auto const actRec = spillStack();
auto const objCls = gen(LdObjClass, obj);
// This is special. We need to move the stackpointer incase LdObjMethod
// calls a destructor. Otherwise it would clobber the ActRec we just pushed.
emitMarker();
gen(LdObjMethod,
objCls,
cns(methodName),
+8
Ver Arquivo
@@ -539,6 +539,14 @@ void methodCacheSlowPath(MethodCache::Pair* mce,
ObjectData* arThis = ar->getThis();
shouldBeObj->m_type = KindOfObject;
shouldBeObj->m_data.pobj = arThis;
// There used to be a half-built ActRec on the stack that we need the
// unwinder to ignore. We overwrote 1/3 of it with the code above, but
// because of the emitMarker() in LdObjMethod we need the other two slots
// to not have any TypedValues.
tvWriteNull(shouldBeObj-1);
tvWriteNull(shouldBeObj-2);
throw;
}
}
+19
Ver Arquivo
@@ -0,0 +1,19 @@
<?php
class A {
public static function factory() {
return new A;
}
public static function b() {
return 'no segfault';
}
public function __destruct() {
}
}
function main() {
echo A::factory()->b();
}
main();
@@ -0,0 +1 @@
no segfault
+22 -1
Ver Arquivo
@@ -1,3 +1,24 @@
<?php
function nop($en,$es){};set_error_handler('nop');class X { function bar() { var_dump($this); } }if (1) { class U { }} else { class U extends X { }}class V extends U {}function test() { $x = new X; $x->bar(); $x = new V; $x->bar();}test();
function nop($en,$es){};
set_error_handler('nop');
class X {
function bar() {
var_dump($this);
}
}
if (1) {
class U { }
} else {
class U extends X { }
}
class V extends U {}
function test() {
$x = new X;
$x->bar();
$x = new V;
$x->bar();
}
test();