From c370f88fb18eecc33650ec3ce06f7bdcc11d1596 Mon Sep 17 00:00:00 2001 From: Paul Yang Date: Thu, 7 Dec 2017 11:16:47 -0800 Subject: Recursively clear unknown fields in submessages. (#3982) * Recursively clear unknown fields in submessages. * Recursively discard unknown fields in submsg for c extension * Fix zts build * Add comment for tests * Add a TODO to add a util for encoding varint for better readability. * Add test for oneof message field. --- php/ext/google/protobuf/encode_decode.c | 95 +++++++++++++++++++++++++++++++-- 1 file changed, 92 insertions(+), 3 deletions(-) (limited to 'php/ext') diff --git a/php/ext/google/protobuf/encode_decode.c b/php/ext/google/protobuf/encode_decode.c index ae5a61f5..b98121bb 100644 --- a/php/ext/google/protobuf/encode_decode.c +++ b/php/ext/google/protobuf/encode_decode.c @@ -1402,7 +1402,6 @@ static void putarray(zval* array, const upb_fielddef* f, upb_sink* sink, RepeatedField* intern = UNBOX(RepeatedField, array); HashTable *ht = PHP_PROTO_HASH_OF(intern->array); size = zend_hash_num_elements(ht); - // size = zend_hash_num_elements(PHP_PROTO_HASH_OF(intern->array)); if (size == 0) return; upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink); @@ -1615,11 +1614,101 @@ PHP_METHOD(Message, mergeFromJsonString) { } } -PHP_METHOD(Message, discardUnknownFields) { - MessageHeader* msg = UNBOX(MessageHeader, getThis()); +// TODO(teboring): refactoring with putrawmsg +static void discard_unknown_fields(MessageHeader* msg) { + upb_msg_field_iter it; + stringsink* unknown = DEREF(message_data(msg), 0, stringsink*); if (unknown != NULL) { stringsink_uninit(unknown); DEREF(message_data(msg), 0, stringsink*) = NULL; } + + // Recursively discard unknown fields of submessages. + Descriptor* desc = msg->descriptor; + TSRMLS_FETCH(); + for (upb_msg_field_begin(&it, desc->msgdef); + !upb_msg_field_done(&it); + upb_msg_field_next(&it)) { + upb_fielddef* f = upb_msg_iter_field(&it); + uint32_t offset = desc->layout->fields[upb_fielddef_index(f)].offset; + bool containing_oneof = false; + + if (upb_fielddef_containingoneof(f)) { + uint32_t oneof_case_offset = + desc->layout->fields[upb_fielddef_index(f)].case_offset; + // For a oneof, check that this field is actually present -- skip all the + // below if not. + if (DEREF(message_data(msg), oneof_case_offset, uint32_t) != + upb_fielddef_number(f)) { + continue; + } + // Otherwise, fall through to the appropriate singular-field handler + // below. + containing_oneof = true; + } + + if (is_map_field(f)) { + MapIter map_it; + int len, size; + const upb_fielddef* value_field; + + value_field = map_field_value(f); + if (!upb_fielddef_issubmsg(value_field)) continue; + + zval* map_php = CACHED_PTR_TO_ZVAL_PTR( + DEREF(message_data(msg), offset, CACHED_VALUE*)); + if (map_php == NULL) continue; + + Map* intern = UNBOX(Map, map_php); + for (map_begin(map_php, &map_it TSRMLS_CC); + !map_done(&map_it); map_next(&map_it)) { + upb_value value = map_iter_value(&map_it, &len); + void* memory = raw_value(upb_value_memory(&value), value_field); +#if PHP_MAJOR_VERSION < 7 + MessageHeader *submsg = UNBOX(MessageHeader, *(zval**)memory); +#else + MessageHeader *submsg = + (MessageHeader*)((char*)(Z_OBJ_P((zval*)memory)) - + XtOffsetOf(MessageHeader, std)); +#endif + discard_unknown_fields(submsg); + } + } else if (upb_fielddef_isseq(f)) { + if (!upb_fielddef_issubmsg(f)) continue; + + zval* array_php = CACHED_PTR_TO_ZVAL_PTR( + DEREF(message_data(msg), offset, CACHED_VALUE*)); + if (array_php == NULL) continue; + + int size, i; + RepeatedField* intern = UNBOX(RepeatedField, array_php); + HashTable *ht = PHP_PROTO_HASH_OF(intern->array); + size = zend_hash_num_elements(ht); + if (size == 0) continue; + + for (i = 0; i < size; i++) { + void* memory = repeated_field_index_native(intern, i TSRMLS_CC); +#if PHP_MAJOR_VERSION < 7 + MessageHeader *submsg = UNBOX(MessageHeader, *(zval**)memory); +#else + MessageHeader *submsg = + (MessageHeader*)((char*)(Z_OBJ_P((zval*)memory)) - + XtOffsetOf(MessageHeader, std)); +#endif + discard_unknown_fields(submsg); + } + } else if (upb_fielddef_issubmsg(f)) { + zval* submsg_php = CACHED_PTR_TO_ZVAL_PTR( + DEREF(message_data(msg), offset, CACHED_VALUE*)); + if (Z_TYPE_P(submsg_php) == IS_NULL) continue; + MessageHeader* submsg = UNBOX(MessageHeader, submsg_php); + discard_unknown_fields(submsg); + } + } +} + +PHP_METHOD(Message, discardUnknownFields) { + MessageHeader* msg = UNBOX(MessageHeader, getThis()); + discard_unknown_fields(msg); } -- cgit v1.2.3