protobuf/php/ext/google/protobuf/protobuf.c
Go to the documentation of this file.
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc. All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 // * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 // * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 // * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 #include "protobuf.h"
32 
33 #include <php.h>
34 #include <Zend/zend_interfaces.h>
35 
36 #include "arena.h"
37 #include "array.h"
38 #include "convert.h"
39 #include "def.h"
40 #include "map.h"
41 #include "message.h"
42 #include "names.h"
43 
44 // -----------------------------------------------------------------------------
45 // Module "globals"
46 // -----------------------------------------------------------------------------
47 
48 // Despite the name, module "globals" are really thread-locals:
49 // * PROTOBUF_G(var) accesses the thread-local variable for 'var'. Either:
50 // * PROTOBUF_G(var) -> protobuf_globals.var (Non-ZTS / non-thread-safe)
51 // * PROTOBUF_G(var) -> <Zend magic> (ZTS / thread-safe builds)
52 
53 #define PROTOBUF_G(v) ZEND_MODULE_GLOBALS_ACCESSOR(protobuf, v)
54 
55 ZEND_BEGIN_MODULE_GLOBALS(protobuf)
56  // Set by the user to make the descriptor pool persist between requests.
58 
59  // Currently we make the generated pool a "global", which means that if a user
60  // does explicitly create threads within their request, the other threads will
61  // get different results from DescriptorPool::getGeneratedPool(). We require
62  // that all descriptors are loaded from the main thread.
64 
65  // A upb_symtab that we are saving for the next request so that we don't have
66  // to rebuild it from scratch. When keep_descriptor_pool_after_request==true,
67  // we steal the upb_symtab from the global DescriptorPool object just before
68  // destroying it.
70 
71  // Object cache (see interface in protobuf.h).
72  HashTable object_cache;
73 
74  // Name cache (see interface in protobuf.h).
75  HashTable name_msg_cache;
76  HashTable name_enum_cache;
77 
78  // An array of descriptor objects constructed during this request. These are
79  // logically referenced by the corresponding class entry, but since we can't
80  // actually write a class entry destructor, we reference them here, to be
81  // destroyed on request shutdown.
82  HashTable descriptors;
83 ZEND_END_MODULE_GLOBALS(protobuf)
84 
85 void free_protobuf_globals(zend_protobuf_globals *globals) {
86  zend_hash_destroy(&globals->name_msg_cache);
87  zend_hash_destroy(&globals->name_enum_cache);
88  upb_symtab_free(globals->global_symtab);
89  globals->global_symtab = NULL;
90 }
91 
93 
95  return &PROTOBUF_G(generated_pool);
96 }
97 
98 // This is a PHP extension (not a Zend extension). What follows is a summary of
99 // a PHP extension's lifetime and when various handlers are called.
100 //
101 // * PHP_GINIT_FUNCTION(protobuf) / PHP_GSHUTDOWN_FUNCTION(protobuf)
102 // are the constructor/destructor for the globals. The sequence over the
103 // course of a process lifetime is:
104 //
105 // # Process startup
106 // GINIT(<Main Thread Globals>)
107 // MINIT
108 //
109 // foreach request:
110 // RINIT
111 // # Request is processed here.
112 // RSHUTDOWN
113 //
114 // foreach thread:
115 // GINIT(<This Thread Globals>)
116 // # Code for the thread runs here.
117 // GSHUTDOWN(<This Thread Globals>)
118 //
119 // # Process Shutdown
120 // #
121 // # These should be running per the docs, but I have not been able to
122 // # actually get the process-wide shutdown functions to run.
123 // #
124 // # MSHUTDOWN
125 // # GSHUTDOWN(<Main Thread Globals>)
126 //
127 // * Threads can be created either explicitly by the user, inside a request,
128 // or implicitly by the runtime, to process multiple requests concurrently.
129 // If the latter is being used, then the "foreach thread" block above
130 // actually looks like this:
131 //
132 // foreach thread:
133 // GINIT(<This Thread Globals>)
134 // # A non-main thread will only receive requests when using a threaded
135 // # MPM with Apache
136 // foreach request:
137 // RINIT
138 // # Request is processed here.
139 // RSHUTDOWN
140 // GSHUTDOWN(<This Thread Globals>)
141 //
142 // That said, it appears that few people use threads with PHP:
143 // * The pthread package documented at
144 // https://www.php.net/manual/en/class.thread.php nas not been released
145 // since 2016, and the current release fails to compile against any PHP
146 // newer than 7.0.33.
147 // * The GitHub master branch supports 7.2+, but this has not been released
148 // to PECL.
149 // * Its owner has disavowed it as "broken by design" and "in an untenable
150 // position for the future": https://github.com/krakjoe/pthreads/issues/929
151 // * The only way to use PHP with requests in different threads is to use the
152 // Apache 2 mod_php with the "worker" MPM. But this is explicitly
153 // discouraged by the documentation: https://serverfault.com/a/231660
154 
156  if (protobuf_globals->global_symtab) {
157  free_protobuf_globals(protobuf_globals);
158  }
159 }
160 
162  ZVAL_NULL(&protobuf_globals->generated_pool);
163  protobuf_globals->global_symtab = NULL;
164 }
165 
172  // Create the global generated pool.
173  // Reuse the symtab (if any) left to us by the last request.
175  if (!symtab) {
177  zend_hash_init(&PROTOBUF_G(name_msg_cache), 64, NULL, NULL, 0);
178  zend_hash_init(&PROTOBUF_G(name_enum_cache), 64, NULL, NULL, 0);
179  }
181 
182  zend_hash_init(&PROTOBUF_G(object_cache), 64, NULL, NULL, 0);
183  zend_hash_init(&PROTOBUF_G(descriptors), 64, NULL, ZVAL_PTR_DTOR, 0);
184 
185  return SUCCESS;
186 }
187 
194  // Preserve the symtab if requested.
196  free_protobuf_globals(ZEND_MODULE_GLOBALS_BULK(protobuf));
197  }
198 
199  zval_dtor(&PROTOBUF_G(generated_pool));
200  zend_hash_destroy(&PROTOBUF_G(object_cache));
201  zend_hash_destroy(&PROTOBUF_G(descriptors));
202 
203  return SUCCESS;
204 }
205 
206 // -----------------------------------------------------------------------------
207 // Object Cache.
208 // -----------------------------------------------------------------------------
209 
210 void Descriptors_Add(zend_object *desc) {
211  // The hash table will own a ref (it will destroy it when the table is
212  // destroyed), but for some reason the insert operation does not add a ref, so
213  // we do that here with ZVAL_OBJ_COPY().
214  zval zv;
215  ZVAL_OBJ_COPY(&zv, desc);
216  zend_hash_next_index_insert(&PROTOBUF_G(descriptors), &zv);
217 }
218 
219 void ObjCache_Add(const void *upb_obj, zend_object *php_obj) {
220  zend_ulong k = (zend_ulong)upb_obj;
221  zend_hash_index_add_ptr(&PROTOBUF_G(object_cache), k, php_obj);
222 }
223 
224 void ObjCache_Delete(const void *upb_obj) {
225  if (upb_obj) {
226  zend_ulong k = (zend_ulong)upb_obj;
227  int ret = zend_hash_index_del(&PROTOBUF_G(object_cache), k);
229  }
230 }
231 
232 bool ObjCache_Get(const void *upb_obj, zval *val) {
233  zend_ulong k = (zend_ulong)upb_obj;
234  zend_object *obj = zend_hash_index_find_ptr(&PROTOBUF_G(object_cache), k);
235 
236  if (obj) {
237  ZVAL_OBJ_COPY(val, obj);
238  return true;
239  } else {
240  ZVAL_NULL(val);
241  return false;
242  }
243 }
244 
245 // -----------------------------------------------------------------------------
246 // Name Cache.
247 // -----------------------------------------------------------------------------
248 
251  zend_hash_str_add_ptr(&PROTOBUF_G(name_msg_cache), k, strlen(k), (void*)m);
252  free(k);
253 }
254 
255 void NameMap_AddEnum(const upb_enumdef *e) {
257  zend_hash_str_add_ptr(&PROTOBUF_G(name_enum_cache), k, strlen(k), (void*)e);
258  free(k);
259 }
260 
261 const upb_msgdef *NameMap_GetMessage(zend_class_entry *ce) {
262  const upb_msgdef *ret =
263  zend_hash_find_ptr(&PROTOBUF_G(name_msg_cache), ce->name);
264 
265  if (!ret && ce->create_object) {
266 #if PHP_VERSION_ID < 80000
267  zval tmp;
268  zval zv;
269  ZVAL_OBJ(&tmp, ce->create_object(ce));
270  zend_call_method_with_0_params(&tmp, ce, NULL, "__construct", &zv);
271  zval_ptr_dtor(&tmp);
272 #else
273  zval zv;
274  zend_object *tmp = ce->create_object(ce);
275  zend_call_method_with_0_params(tmp, ce, NULL, "__construct", &zv);
276  OBJ_RELEASE(tmp);
277 #endif
278  zval_ptr_dtor(&zv);
279  ret = zend_hash_find_ptr(&PROTOBUF_G(name_msg_cache), ce->name);
280  }
281 
282  return ret;
283 }
284 
285 const upb_enumdef *NameMap_GetEnum(zend_class_entry *ce) {
286  const upb_enumdef *ret =
287  zend_hash_find_ptr(&PROTOBUF_G(name_enum_cache), ce->name);
288  return ret;
289 }
290 
291 // -----------------------------------------------------------------------------
292 // Module init.
293 // -----------------------------------------------------------------------------
294 
295 zend_function_entry protobuf_functions[] = {
296  ZEND_FE_END
297 };
298 
299 static const zend_module_dep protobuf_deps[] = {
300  ZEND_MOD_OPTIONAL("date")
301  ZEND_MOD_END
302 };
303 
304 PHP_INI_BEGIN()
306  PHP_INI_ALL, OnUpdateBool,
307  keep_descriptor_pool_after_request, zend_protobuf_globals,
308  protobuf_globals)
309 PHP_INI_END()
310 
312  REGISTER_INI_ENTRIES();
316  Def_ModuleInit();
317  Map_ModuleInit();
319  return SUCCESS;
320 }
321 
323  UNREGISTER_INI_ENTRIES();
324  return SUCCESS;
325 }
326 
327 zend_module_entry protobuf_module_entry = {
328  STANDARD_MODULE_HEADER_EX,
329  NULL,
331  "protobuf", // extension name
332  protobuf_functions, // function list
333  PHP_MINIT(protobuf), // process startup
334  PHP_MSHUTDOWN(protobuf), // process shutdown
335  PHP_RINIT(protobuf), // request shutdown
336  PHP_RSHUTDOWN(protobuf), // request shutdown
337  NULL, // extension info
338  PHP_PROTOBUF_VERSION, // extension version
339  PHP_MODULE_GLOBALS(protobuf), // globals descriptor
340  PHP_GINIT(protobuf), // globals ctor
341  PHP_GSHUTDOWN(protobuf), // globals dtor
342  NULL, // post deactivate
343  STANDARD_MODULE_PROPERTIES_EX
344 };
345 
346 ZEND_GET_MODULE(protobuf)
upb_msgdef_file
const upb_filedef * upb_msgdef_file(const upb_msgdef *m)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:3536
Def_ModuleInit
void Def_ModuleInit()
Definition: protobuf/php/ext/google/protobuf/def.c:1051
obj
OPENSSL_EXPORT const ASN1_OBJECT * obj
Definition: x509.h:1671
ObjCache_Add
void ObjCache_Add(const void *upb_obj, zend_object *php_obj)
Definition: protobuf/php/ext/google/protobuf/protobuf.c:219
const
#define const
Definition: bloaty/third_party/zlib/zconf.h:230
PBPHP_ASSERT
#define PBPHP_ASSERT(x)
Definition: protobuf/php/ext/google/protobuf/protobuf.h:139
upb_symtab_new
upb_symtab * upb_symtab_new(void)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:4545
ObjCache_Get
bool ObjCache_Get(const void *upb_obj, zval *val)
Definition: protobuf/php/ext/google/protobuf/protobuf.c:232
upb_enumdef_fullname
const char * upb_enumdef_fullname(const upb_enumdef *e)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:3244
PHP_RINIT_FUNCTION
static PHP_RINIT_FUNCTION(protobuf)
Definition: protobuf/php/ext/google/protobuf/protobuf.c:171
upb_symtab_free
void upb_symtab_free(upb_symtab *s)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:4540
google::protobuf
Definition: bloaty/third_party/protobuf/benchmarks/util/data_proto2_to_proto3_util.h:12
upb_enumdef_file
const upb_filedef * upb_enumdef_file(const upb_enumdef *e)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:3252
ZVAL_OBJ
#define ZVAL_OBJ(zval_ptr, call_create)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/protobuf.h:238
setup.k
k
Definition: third_party/bloaty/third_party/capstone/bindings/python/setup.py:42
protobuf.h
NameMap_AddEnum
void NameMap_AddEnum(const upb_enumdef *e)
Definition: protobuf/php/ext/google/protobuf/protobuf.c:255
message.h
Descriptors_Add
void Descriptors_Add(zend_object *desc)
Definition: protobuf/php/ext/google/protobuf/protobuf.c:210
Arena_ModuleInit
void Arena_ModuleInit()
Definition: arena.c:84
array.h
keep_descriptor_pool_after_request
zend_bool keep_descriptor_pool_after_request
Definition: protobuf/php/ext/google/protobuf/protobuf.c:57
Array_ModuleInit
void Array_ModuleInit()
Definition: protobuf/php/ext/google/protobuf/array.c:634
upb_msgdef_fullname
const char * upb_msgdef_fullname(const upb_msgdef *m)
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:3532
object_cache
HashTable object_cache
Definition: protobuf/php/ext/google/protobuf/protobuf.c:72
get_generated_pool
const zval * get_generated_pool()
Definition: protobuf/php/ext/google/protobuf/protobuf.c:94
Map_ModuleInit
void Map_ModuleInit()
Definition: protobuf/php/ext/google/protobuf/map.c:631
name_msg_cache
HashTable name_msg_cache
Definition: protobuf/php/ext/google/protobuf/protobuf.c:75
NameMap_GetMessage
const upb_msgdef * NameMap_GetMessage(zend_class_entry *ce)
Definition: protobuf/php/ext/google/protobuf/protobuf.c:261
arena.h
name_enum_cache
HashTable name_enum_cache
Definition: protobuf/php/ext/google/protobuf/protobuf.c:76
ObjCache_Delete
void ObjCache_Delete(const void *upb_obj)
Definition: protobuf/php/ext/google/protobuf/protobuf.c:224
protobuf_deps
static const zend_module_dep protobuf_deps[]
Definition: protobuf/php/ext/google/protobuf/protobuf.c:299
PHP_PROTOBUF_VERSION
#define PHP_PROTOBUF_VERSION
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/protobuf.h:40
upb_symtab
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:3018
def.h
PROTOBUF_G
#define PROTOBUF_G(v)
Definition: protobuf/php/ext/google/protobuf/protobuf.c:53
PHP_MINIT_FUNCTION
PHP_MINIT_FUNCTION(grpc)
Definition: php_grpc.c:286
free_protobuf_globals
void free_protobuf_globals(zend_protobuf_globals *globals)
Definition: protobuf/php/ext/google/protobuf/protobuf.c:85
ZVAL_OBJ_COPY
#define ZVAL_OBJ_COPY(z, o)
Definition: protobuf/php/ext/google/protobuf/protobuf.h:64
grpc::testing::SUCCESS
@ SUCCESS
Definition: h2_ssl_cert_test.cc:201
symtab
upb_symtab * symtab
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/protobuf.h:774
PHP_RSHUTDOWN_FUNCTION
static PHP_RSHUTDOWN_FUNCTION(protobuf)
Definition: protobuf/php/ext/google/protobuf/protobuf.c:193
Message_ModuleInit
void Message_ModuleInit()
Definition: protobuf/php/ext/google/protobuf/message.c:1368
ZEND_DECLARE_MODULE_GLOBALS
ZEND_DECLARE_MODULE_GLOBALS(grpc)
NameMap_AddMessage
void NameMap_AddMessage(const upb_msgdef *m)
Definition: protobuf/php/ext/google/protobuf/protobuf.c:249
upb_enumdef
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:2984
Convert_ModuleInit
void Convert_ModuleInit(void)
Definition: protobuf/php/ext/google/protobuf/convert.c:506
PHP_MSHUTDOWN_FUNCTION
static PHP_MSHUTDOWN_FUNCTION(protobuf)
Definition: protobuf/php/ext/google/protobuf/protobuf.c:322
PHP_GINIT_FUNCTION
static PHP_GINIT_FUNCTION(protobuf)
Definition: protobuf/php/ext/google/protobuf/protobuf.c:161
ret
UniquePtr< SSL_SESSION > ret
Definition: ssl_x509.cc:1029
protobuf_functions
zend_function_entry protobuf_functions[]
Definition: protobuf/php/ext/google/protobuf/protobuf.c:295
desc
#define desc
Definition: bloaty/third_party/protobuf/src/google/protobuf/extension_set.h:338
protobuf_module_entry
zend_module_entry protobuf_module_entry
Definition: protobuf/php/ext/google/protobuf/protobuf.c:327
STD_PHP_INI_ENTRY
STD_PHP_INI_ENTRY("protobuf.keep_descriptor_pool_after_request", "0", PHP_INI_ALL, OnUpdateBool, keep_descriptor_pool_after_request, zend_protobuf_globals, protobuf_globals)
Definition: protobuf/php/ext/google/protobuf/protobuf.c:305
global_symtab
upb_symtab * global_symtab
Definition: protobuf/php/ext/google/protobuf/protobuf.c:69
names.h
autogen_x86imm.tmp
tmp
Definition: autogen_x86imm.py:12
NameMap_GetEnum
const upb_enumdef * NameMap_GetEnum(zend_class_entry *ce)
Definition: protobuf/php/ext/google/protobuf/protobuf.c:285
generated_pool
zval generated_pool
Definition: protobuf/php/ext/google/protobuf/protobuf.c:63
GetPhpClassname
char * GetPhpClassname(const upb_filedef *file, const char *fullname)
Definition: names.c:210
descriptors
HashTable descriptors
Definition: protobuf/php/ext/google/protobuf/protobuf.c:82
DescriptorPool_CreateWithSymbolTable
void DescriptorPool_CreateWithSymbolTable(zval *zv, upb_symtab *symtab)
Definition: protobuf/php/ext/google/protobuf/def.c:746
regress.m
m
Definition: regress/regress.py:25
PHP_GSHUTDOWN_FUNCTION
static PHP_GSHUTDOWN_FUNCTION(protobuf)
Definition: protobuf/php/ext/google/protobuf/protobuf.c:155
upb_msgdef
Definition: bloaty/third_party/protobuf/php/ext/google/protobuf/upb.c:2962
map.h
convert.h


grpc
Author(s):
autogenerated on Fri May 16 2025 02:59:47