Skip to content

Conversation

@Hiroya-W
Copy link

@Hiroya-W Hiroya-W commented Jan 19, 2026

Hello! I have found a solution to the issue in #22173, so I would like you to review it.

Problem

When attempting to iterate over a protobuf Message object using PHP's foreach construct, a segmentation fault occurs. This happens because the get_properties object handler returns NULL, which causes the Zend engine to dereference a null pointer when attempting iteration.

$msg = new \Example\ProtoMessage();
foreach ($msg as $key => $value) {  // Segmentation fault
    // ...
}

Root Cause

The issue occurs in three object handlers:

  • Message_get_properties() in message.c

All three handlers were returning NULL with the comment "We don't have/offer a properties table." While this is intentional (protobuf messages are not meant to be iterable), returning NULL causes the Zend engine to crash when PHP's foreach tries to use the result.

From the stack trace in #22173:

#0  ZEND_FE_RESET_R_SPEC_CV_HANDLER () at ./Zend/zend_hash.h:317
#1  zend_vm_call_opcode_handler (ex=ex@entry=0x7fe88d214020) at ./Zend/zend_vm_execute.h:68448

The crash happens at zend_hash.h:317 where zend_hash_num_elements(ht) is called with a NULL pointer.

Solution

Instead of returning NULL, we now ensure that a valid (but empty) HashTable is returned by calling zend_std_get_properties(). This is the standard Zend API function that:

  1. Initializes object->properties if it doesn't exist
  2. Returns an empty but valid HashTable
  3. Prevents the segmentation fault while maintaining the expected behavior (no properties to iterate)

Changes Made

  1. php/ext/google/protobuf/message.c: Modified Message_get_properties() to call zend_std_get_properties() and return a valid HashTable
  2. php/tests/GeneratedClassTest.php: Added regression test testForeachOnMessageDoesNotSegfault()

Testing

Manual Test

<?php
require 'build/gen/GPBMetadata/Message.php';
require 'build/gen/Example/ProtoMessage.php';

echo "iterating generated php class ProtoMessage\n";

$proto_msg = new \Example\ProtoMessage();
foreach ($proto_msg as $key => $value) {
    assert(false);  // Should not iterate any elements
}
echo "SUCCESS: No segmentation fault\n";

Before fix: Segmentation fault
After fix: No crash, zero iterations (expected behavior)

Unit Test

Added testForeachOnMessageDoesNotSegfault() in GeneratedClassTest.php:

  • Creates a TestMessage with some fields set
  • Attempts to iterate with foreach
  • Verifies no segfault occurs

Build and Test

composer install
composer test_c

Expected Behavior

After this fix:

  • ✅ No segmentation fault when using foreach on Message objects
  • ✅ Foreach completes gracefully with zero iterations (messages are not meant to be iterable)
  • ✅ All existing functionality remains unchanged
  • ✅ RepeatedField and MapField continue to work correctly with their IteratorAggregate implementation

Compatibility

  • Tested on PHP 8.4.1 and PHP 8.5.0
  • Uses standard Zend API (zend_std_get_properties) available in all PHP versions
  • No breaking changes to existing code
  • Backward compatible with all PHP versions that protobuf supports

Related Issues

@Hiroya-W Hiroya-W force-pushed the yuyukun/fix-php-iterate-segment-fault branch from 03e6159 to c65efd6 Compare January 19, 2026 11:10
@Hiroya-W Hiroya-W force-pushed the yuyukun/fix-php-iterate-segment-fault branch from c65efd6 to 7956d90 Compare January 19, 2026 11:25
@Hiroya-W Hiroya-W marked this pull request as ready for review January 19, 2026 11:27
@Hiroya-W Hiroya-W requested a review from a team as a code owner January 19, 2026 11:27
@Hiroya-W Hiroya-W requested review from ericsalo and removed request for a team January 19, 2026 11:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Iterating a \Google\Protobuf\Internal\Message PHP object segfaults when using the protobuf extension

1 participant