THRIFT-4263: Fix use after free bug for thrown exceptions
Client: php

Exceptions thrown through PHPExceptionWrapper are prematurely freed at the end
of the catch block, even though zend_throw_exception_object expects to take
ownership of the value.

Ensure we free return_value in case of exceptions

Patch: HÃ¥kon Hitland <hakon.hitland@zedge.net>
Patch: Roy Sindre Norangshol <norangshol@zedge.net>

This closes #1314
diff --git a/test/php/TestClient.php b/test/php/TestClient.php
index 76fd935..1591027 100755
--- a/test/php/TestClient.php
+++ b/test/php/TestClient.php
@@ -492,6 +492,25 @@
   print_r(' caught xception '.$x->errorCode.': '.$x->message."\n");
 }
 
+// Regression test for THRIFT-4263
+print_r("testBinarySerializer_Deserialize('foo')");
+try {
+  \Thrift\Serializer\TBinarySerializer::deserialize(base64_decode('foo'), \ThriftTest\Xtruct2::class);
+  echo "**FAILED**\n";
+  $exitcode |= ERR_STRUCTS;
+} catch (\Thrift\Exception\TTransportException $happy_exception) {
+  // We expected this due to binary data of base64_decode('foo') is less then 4
+  // bytes and it tries to find thrift version number in the transport by
+  // reading i32() at the beginning.  Casting to string validates that
+  // exception is still accessible in memory and not corrupted.  Without patch,
+  // PHP will error log that the exception doesn't have any tostring method,
+  // which is a lie due to corrupted memory.
+  for($i=99; $i > 0; $i--) {
+    (string)$happy_exception;
+  }
+  print_r("  SUCCESS\n");
+}
+
 /**
  * Normal tests done.
  */