From 1069565a68654fa016cb454c87eca8372b3b8d3f Mon Sep 17 00:00:00 2001 From: Paul Yang Date: Tue, 22 Jan 2019 14:02:44 -0800 Subject: [PATCH] Fix c extension doesn' allow message reference in array (#5599) * Fix c extension doesn' allow message reference in array * Fix array constructor handling reference of array. * Change test name --- php/ext/google/protobuf/message.c | 5 +++++ php/ext/google/protobuf/storage.c | 6 ++++++ php/tests/array_test.php | 31 +++++++++++++++++++++++++++++++ php/tests/proto/test.proto | 1 + 4 files changed, 43 insertions(+) diff --git a/php/ext/google/protobuf/message.c b/php/ext/google/protobuf/message.c index d883340f06..079bd1dd45 100644 --- a/php/ext/google/protobuf/message.c +++ b/php/ext/google/protobuf/message.c @@ -319,6 +319,11 @@ void Message_construct(zval* msg, zval* array_wrapper) { zend_hash_move_forward_ex(array, &pointer)) { zend_hash_get_current_key_zval_ex(array, &key, &pointer); field = upb_msgdef_ntofz(intern->descriptor->msgdef, Z_STRVAL_P(&key)); +#if PHP_MAJOR_VERSION >= 7 + if (Z_ISREF_P((CACHED_VALUE*)value)) { + value = Z_REFVAL_P((CACHED_VALUE*)value); + } +#endif if (field == NULL) { zend_error(E_USER_ERROR, "Unknown field: %s", Z_STRVAL_P(&key)); } diff --git a/php/ext/google/protobuf/storage.c b/php/ext/google/protobuf/storage.c index 93a16ddab4..610d3eb75e 100644 --- a/php/ext/google/protobuf/storage.c +++ b/php/ext/google/protobuf/storage.c @@ -186,6 +186,12 @@ bool native_slot_set_by_array(upb_fieldtype_t type, break; } case UPB_TYPE_MESSAGE: { +#if PHP_MAJOR_VERSION >= 7 + if (Z_ISREF_P(value)) { + ZVAL_DEREF(value); + } +#endif + if (Z_TYPE_P(value) != IS_OBJECT) { zend_error(E_USER_ERROR, "Given value is not message."); return false; diff --git a/php/tests/array_test.php b/php/tests/array_test.php index b0084332c9..d47a107765 100644 --- a/php/tests/array_test.php +++ b/php/tests/array_test.php @@ -529,6 +529,37 @@ class RepeatedFieldTest extends \PHPUnit\Framework\TestCase $this->assertSame(3, $arr[2]); } + ######################################################### + # Test reference in array + ######################################################### + + public function testArrayElementIsReference() + { + $m = new TestMessage(); + $subs = [1, 2]; + + foreach ($subs as &$sub) { + $sub = new Sub(['a' => $sub]); + } + + $m->setRepeatedMessage($subs); + } + + public function testArrayIsReference() + { + $keys = [['repeated_message' => [['a' => 1]]]]; + + foreach ($keys as &$key) { + foreach ($key['repeated_message'] as &$element) { + $element = new Sub($element); + } + $key = new TestMessage($key); + } + + $m = new TestMessage(); + $m->setRepeatedDeep($keys); + } + ######################################################### # Test memory leak ######################################################### diff --git a/php/tests/proto/test.proto b/php/tests/proto/test.proto index e610c581b5..ca39ea46a4 100644 --- a/php/tests/proto/test.proto +++ b/php/tests/proto/test.proto @@ -31,6 +31,7 @@ message TestMessage { Sub optional_message = 17; bar.TestInclude optional_included_message = 18; TestMessage recursive = 19; + repeated TestMessage repeated_deep = 20; // Repeated repeated int32 repeated_int32 = 31;