fix for ConvToString

When we do CastString on an object, the ConvObjToStr helper
may throw if it does not have a __toString() function.
When spilling the stack before calling the helper,
we must push back the popped object.

Also convObjToString helper should not decref its object if the conversion failed.
Esse commit está contido em:
aravind
2013-04-18 12:17:24 -07:00
commit de Sara Golemon
commit 97766b0367
5 arquivos alterados com 89 adições e 28 exclusões
@@ -102,9 +102,19 @@ int64_t convStrToDblHelper(const StringData* s) {
}
int64_t convCellToDblHelper(TypedValue tv) {
tvCastToDoubleInPlace(&tv); // consumes a ref on counted values
// but not if an exception happens. (REVIEW)
return tv.m_data.num;
try {
tvCastToDoubleInPlace(&tv); // consumes a ref on counted values
// but not if an exception happens. (REVIEW)
return tv.m_data.num;
} catch (...) {
// spill tv back to stack. unwinder
// will take care of decreffing it.
VMRegAnchor _;
TypedValue* spillSlot = (TypedValue *)vmsp();
spillSlot->m_data.num = tv.m_data.num;
spillSlot->m_type = tv.m_type;
throw;
}
}
int64_t convArrToIntHelper(ArrayData* a) {
@@ -122,9 +132,19 @@ int64_t convStrToIntHelper(const StringData* s) {
}
int64_t convCellToIntHelper(TypedValue tv) {
tvCastToInt64InPlace(&tv); // consumes a ref on counted values
// but not if an exception happens. (REVIEW)
return tv.m_data.num;
try {
tvCastToInt64InPlace(&tv); // consumes a ref on counted values
// but not if an exception happens. (REVIEW)
return tv.m_data.num;
} catch (...) {
// spill tv back to stack. unwinder
// will take care of decreffing it.
VMRegAnchor _;
TypedValue* spillSlot = (TypedValue *)vmsp();
spillSlot->m_data.num = tv.m_data.num;
spillSlot->m_type = tv.m_type;
throw;
}
}
ObjectData* convCellToObjHelper(TypedValue tv) {
@@ -157,11 +177,16 @@ StringData* convObjToStrHelper(ObjectData* o) {
try {
auto s = o->t___tostring();
auto r = s.get();
o->decRefCount();
decRefObj(o);
if (!r->isStatic()) r->incRefCount();
return r;
} catch (...) {
o->decRefCount();
// spill object back to stack. unwinder
// will take care of decreffing it.
VMRegAnchor _;
TypedValue* spillSlot = (TypedValue *)vmsp();
spillSlot->m_data.pobj = o;
spillSlot->m_type = KindOfObject;
throw;
}
}
+50
Ver Arquivo
@@ -0,0 +1,50 @@
<?php ;
class X {
function not__toString() { throw new Exception('boom'); }
}
function error_handler() {
throw new Exception("user error handler");
}
//set_error_handler('error_handler');
function foo($x) {
return $x;
}
function testStr($x) {
return foo((string)$x);
}
function testInt($x) {
return foo((int)$x);
}
function testDbl($x) {
return foo((double)$x);
}
echo "test int\n";
try {
testInt(new X);
} catch (Exception $e) {
var_dump($e->getMessage());
}
echo "test dbl\n";
try {
testDbl(new X);
} catch (Exception $e) {
var_dump($e->getMessage());
}
echo "test str\n";
try {
testStr(new X);
} catch (Exception $e) {
var_dump($e->getMessage());
}
+6
Ver Arquivo
@@ -0,0 +1,6 @@
test int
HipHop Notice: Object of class X could not be converted to int in %s on line 21
test dbl
HipHop Notice: Object of class X could not be converted to int in %s on line 25
test str
HipHop Fatal error: Bad type conversion: X::__toString() was not defined. in %s on line 17
-19
Ver Arquivo
@@ -1,19 +0,0 @@
<?php ;
class X {
function not__toString() { throw new Exception('boom'); }
}
function foo($x) {
return $x;
}
function test($x) {
return foo((string)$x);
}
try {
test(new X);
} catch (Exception $e) {
var_dump($e->getMessage());
}
-1
Ver Arquivo
@@ -1 +0,0 @@
HipHop Fatal error: Bad type conversion: X::__toString() was not defined. in %s on line 12