allegro/php-protobuf

ZTS Support: Error while building protobuf.c: tsrm_ls undeclared

avengerx opened this issue · 2 comments

I'm using gentoo linux on a fresh updated version of PHP (didn't have PDO support which I needed for something else).

$ php --version
PHP 5.6.24-pl0-gentoo (cli) (built: Aug  9 2016 01:50:45)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
    with Zend OPcache v7.0.6-dev, Copyright (c) 1999-2016, by Zend Technologies

During make, I am getting:

libtool: compile:  cc -I. -I/home/avenger/whatsapi/php-protobuf -DPHP_ATOM_INC -I/home/avenger/whatsapi/php-protobuf/include -I/home/avenger/whatsapi/php-protobuf/main -I/home/avenger/whatsapi/php-protobuf -I/usr/lib64/php5.6/include/php -I/usr/lib64/php5.6/include/php/main -I/usr/lib64/php5.6/include/php/TSRM -I/usr/lib64/php5.6/include/php/Zend -I/usr/lib64/php5.6/include/php/ext -I/usr/lib64/php5.6/include/php/ext/date/lib -DHAVE_CONFIG_H -g -O2 -c /home/avenger/whatsapi/php-protobuf/protobuf.c  -fPIC -DPIC -o .libs/protobuf.o
In file included from /usr/lib64/php5.6/include/php/Zend/zend_alloc.h:27:0,
                 from /usr/lib64/php5.6/include/php/Zend/zend.h:252,
                 from /usr/lib64/php5.6/include/php/main/php.h:35,
                 from /home/avenger/whatsapi/php-protobuf/protobuf.c:1:
/home/avenger/whatsapi/php-protobuf/protobuf.c: In function ‘pb_assign_value’:
/usr/lib64/php5.6/include/php/Zend/../TSRM/TSRM.h:167:18: error: ‘tsrm_ls’ undeclared (first use in this function)
 #define TSRMLS_C tsrm_ls
                  ^
/usr/lib64/php5.6/include/php/Zend/../TSRM/TSRM.h:168:21: note: in expansion of macro ‘TSRMLS_C’
 #define TSRMLS_CC , TSRMLS_C
                     ^
/home/avenger/whatsapi/php-protobuf/protobuf.c:24:34: note: in expansion of macro ‘TSRMLS_CC’
  zend_throw_exception_ex(NULL, 0 TSRMLS_CC, "%s: compile error - " #message, Z_OBJCE_P(this)->name, __VA_ARGS__)
                                  ^

What I could find about this missing tsrm_ls is related to PHP with ZTS (zend threads security) enabled and seems that a different approach must be taken while building extensions to PHP using it. To enable ZTS on php, the --enable-maintainer-zts flag should be used.

PHP manual page for this setting: http://php.net/manual/en/internals2.buildsys.environment.php

I'm not sure which gentoo USE flag enabled this in my PHP set up, but I could successfully build and install other extension (https://github.com/mgp25/curve25519-php) with no problem.

I could find some projects that required slight changes in the source files in order to be able to. To name some: phpredis/phpredis#193 and libgeos/geos#9.

I'll try to investigate more on this (for a solution) when I have more time but, if the investigation above helps someone willing to jump in, please don't hesitate!

This seems to be the best documentation (linked from libgeos/geos#9) on how to handle this issue. But as I am not really experienced in building and developing PHP extensions, and I also not familiar to the php-protobuf source code, it might take a lot to me to figure out & fix where it hurts, but may be just easy for someone acquainted with the project. :)

Thread-Safe Resource Manager

Hello! I'm too lazy to create a pull request so I release my fix in open domain here:

diff --git a/protobuf.c b/protobuf.c
index 0bf18b5..21a8deb 100644
--- a/protobuf.c
+++ b/protobuf.c
@@ -58,7 +58,7 @@ enum

 zend_class_entry *pb_entry;

-static int pb_assign_value(zval *this, zval *dst, zval *src, uint32_t field_number);
+static int pb_assign_value(zval *this, zval *dst, zval *src, uint32_t field_number TSRMLS_DC);
 static int pb_print_field_value(zval **value, long level, zend_bool only_set);
 static int pb_dump_field_value(zval **value, long level, zend_bool only_set);
 static int pb_print_debug_field_value(zval **value, long level);
@@ -70,9 +70,9 @@ static int pb_get_wire_type(int field_type);
 static const char *pb_get_wire_type_name(int wire_type);
 static zval **pb_get_value(zval *this, zval **values, uint32_t field_number);
 static zval **pb_get_values(zval *this);
-static int pb_parse_field_value(zval *this, reader_t *reader, long field_number, long field_type, zval *value);
+static int pb_parse_field_value(zval *this, reader_t *reader, long field_number, long field_type, zval *value TSRMLS_DC);
 static int pb_serialize_field_value(zval *this, writer_t *writer, uint32_t field_number, zval **type, zval **value);
-static int pb_serialize_packed_field(zval *this, writer_t *writer, long field_number, long field_type, zval *values);
+static int pb_serialize_packed_field(zval *this, writer_t *writer, long field_number, long field_type, zval *values TSRMLS_DC);

 static ulong PB_FIELD_TYPE_HASH;
 static ulong PB_VALUES_PROPERTY_HASH;
@@ -106,7 +106,7 @@ PHP_METHOD(ProtobufMessage, append)
                RETURN_THIS();

        MAKE_STD_ZVAL(val);
-       if (pb_assign_value(getThis(), val, value, field_number) != 0) {
+       if (pb_assign_value(getThis(), val, value, field_number TSRMLS_CC) != 0) {
                zval_ptr_dtor(&val);
                RETURN_THIS();
        }
@@ -462,7 +462,7 @@ PHP_METHOD(ProtobufMessage, parseFromString)
                                                ALLOC_INIT_ZVAL(value);
                                                add_next_index_zval(*old_value, value);
                                        }
-                                       if (pb_parse_field_value(getThis(), &packed_reader, field_number, Z_LVAL_PP(field_type), value) != 0) {
+                                       if (pb_parse_field_value(getThis(), &packed_reader, field_number, Z_LVAL_PP(field_type), value TSRMLS_CC) != 0) {
                                                return;
                                        }
                                        value = NULL;
@@ -473,7 +473,7 @@ PHP_METHOD(ProtobufMessage, parseFromString)
                                        return;
                                }

-                               if (pb_parse_field_value(getThis(), &reader, field_number, Z_LVAL_PP(field_type), value) != 0) {
+                               if (pb_parse_field_value(getThis(), &reader, field_number, Z_LVAL_PP(field_type), value TSRMLS_CC) != 0) {
                                        return;
                                }
                        }
@@ -532,7 +532,7 @@ PHP_METHOD(ProtobufMessage, serializeToString)
                        array = value;

                        if (zend_hash_find(Z_ARRVAL_PP(field_descriptor), PB_FIELD_PACKED, sizeof(PB_FIELD_PACKED), (void **) &packed) != FAILURE && Z_BVAL_PP(packed)) {
-                               if (pb_serialize_packed_field(getThis(), &writer, field_number, Z_LVAL_PP(type), *array) != 0)
+                               if (pb_serialize_packed_field(getThis(), &writer, field_number, Z_LVAL_PP(type), *array TSRMLS_CC) != 0)
                                        goto fail;
                        } else {
                                PB_FOREACH(&j, Z_ARRVAL_PP(array)) {
@@ -577,7 +577,7 @@ PHP_METHOD(ProtobufMessage, set)
                }
        } else {
                zval_dtor(*old_value);
-               pb_assign_value(getThis(), *old_value, value, field_number);
+               pb_assign_value(getThis(), *old_value, value, field_number TSRMLS_CC);
        }

        RETURN_THIS();
@@ -685,10 +685,9 @@ zend_module_entry protobuf_module_entry = {
 ZEND_GET_MODULE(protobuf)
 #endif

-static int pb_assign_value(zval *this, zval *dst, zval *src, uint32_t field_number)
+static int pb_assign_value(zval *this, zval *dst, zval *src, uint32_t field_number TSRMLS_DC)
 {
        zval **field_descriptor, *field_descriptors, tmp, **type;
-       TSRMLS_FETCH();

        if ((field_descriptors = pb_get_field_descriptors(this)) == NULL)
                goto fail0;
@@ -988,7 +987,7 @@ static zval **pb_get_values(zval *this)
        return values;
 }

-static int pb_parse_field_value(zval *this, reader_t *reader, long field_number, long field_type, zval *value)
+static int pb_parse_field_value(zval *this, reader_t *reader, long field_number, long field_type, zval *value TSRMLS_DC)
 {
        int ret, str_size;
        char *str;
@@ -1115,7 +1114,7 @@ static int pb_serialize_field_value(zval *this, writer_t *writer, uint32_t field
        return 0;
 }

-static int pb_serialize_packed_field(zval *this, writer_t *writer, long field_number, long field_type, zval *values)
+static int pb_serialize_packed_field(zval *this, writer_t *writer, long field_number, long field_type, zval *values TSRMLS_DC)
 {
        int ret = 0;

@@ -1152,4 +1151,4 @@ static int pb_serialize_packed_field(zval *this, writer_t *writer, long field_nu
        }

        return ret;
-}
\ No newline at end of file
+}

Point is: to support ZTS you have to add to related functions:

  • to function prototypes: TSRMLS_DC (or TSRMLS_D if you don't want it to pretend a comma to the function's argument
  • to function calls: TSRMLS_CC (or TSRMLS_C likewise)

There's also a #ifdef ZTS thing that I didn't really try to fiddle with. The changes above were enough to build the package pragmatically and I'll see what happens when running the lib. :B

This blog post helped me understand an actual application of the ZTS rules to an extension: STILL TRYING TO GET IT ALL OUT - What the heck is TSRMLS_CC, anyway? from -- what? -- 2006. :)

I'd better leave this open until someone merges the changes to the code, right? :)