是什么导致我的测试 PHP 扩展出现这种奇怪的内存损坏?

我最近需要一个已编译信号名称的列表,这样我就可以打印出很好的消息,例如“被 SIGINT (2) 中断”。


get_defined_constants()对此无法使用,因为它在完全不相关的定义中(具有相同的整数值)混杂在一起SIGINT等SIGTRAP。


信号名称根据操作系统映射到不同的值,有时它们并没有全部编译到 PHP 中,所以最直接的干净解决方案是一个新函数,它只返回一个已编译的信号名称数组。


嗯……一个将静态数组返回给 PHP 用户空间的函数……这听起来像是一个非常好的第一个源代码黑客项目,对吧?


不 :)


下面的代码(再往下一点)是一个超级最小化的测试用例,它说明了我撞到的非常奇怪的砖墙。


我有一个GINIT函数将扩展全局初始化test_array为一个数组,然后我用一些条目(就像我的更改pcntl所做的那样)填充它add_assoc_long()(在这种情况下sprintf(),用于为数组键生成虚拟字符串,如!!!, """,###等)。


test_test1()然后,我有一个ZVAL_COPY预构建test_array的演示功能return_value。


请打鼓;看看当我尝试和print_r()结果时会发生什么:


Array

(

    [PWD] => 0

    [i336] => 1

    [LOGNAME] => 2

    [tty] => 3

    [HOME] => 4

    [LANG] => 5

    [user] => 6

    [xterm] => 7

    [TERM] => 8

    [i336] => 9

    [USER] => 10

    [:0] => 11

    [DISPLAY] => 12

    [SHLVL] => 13

    [9:22836] => 14

    [PATH] => 15

    [111] => 16

    [222] => 17

    [333] => 18

    [444] => 19

    [555] => 20

    [666] => 21

    [777] => 22

    [888] => 23

    [999] => 24

    [HG] => 25

    [MAIL] => 26

    [OLDPWD] => 27

    [] => 28

    [] => 29

    [] => 30

    [STDIN] => 31

    [STDOUT] => 32

    [STDERR] => 33

    [print_r] => 34

    [DDD] => 35

    [EEE] => 36

    [FFF] => 37

    [GGG] => 38

    [HHH] => 39

    [III] => 40

    [JJJ] => 41

    [KKK] => 42

    [LLL] => 43

    [MMM] => 44

    [NNN] => 45

    [OOO] => 46

    [PPP] => 47

    [QQQ] => 48

    [RRR] => 49

<<snipped>>

真正奇怪的是条目 0 到 15 已损坏。条目 16 到 24 可以;条目 25 到 34 已损坏;条目 35 上很好。


0-15 / 16-24 有一种奇怪的感觉;25-34 / 35-∞没有。

除了一些关于我做错了什么的提示(我知道我有一些倒退...... :) ),我非常想了解为什么PHP 将部分看似随机的环境变量转储到我的数组中!


我停止自己的探索/解决过程并发布此问题的主要原因是我意识到我不知道我不知道什么,再加上我不知道该去哪里尝试解决这。


提供 PHP 文档的资源越来越多,但不幸的是,弄清楚如何完成简单的任务似乎需要将来自不同来源的大量细节拼凑在一起(我被困在表面上看起来很简单的东西上) .


我也有关于我正在阅读的内容的最新程度的问题。


一个例子:ZEND_MODULE_GLOBALS_ACCESSOR()用于线程安全地访问每个模块的全局值的宏被使用了 37 次(看起来只有不到一半的内容ext/)。然而,我读过的所有信息,包括在 phpinternals.net 和 phpinternalsbook.net 等网站上,都指定了包含特定 5 行 #define 的硬性要求,以便设置对模块全局变量的访问。我偶然发现了前面提到的宏,它在 PHP 本身中实现了#define,因此没有人必须通过阅读源代码来自己做。


我可以完全接受事情并不完全同步——也许那个宏是新的。


但是,我在哪里可以找到最新的参考信息来回答我的问题?


沧海一幻觉
浏览 115回答 1
1回答

慕少森

GINIT 在请求启动之前被调用。array_init()并且add_assoc_long()(和大多数其他 API)使用按请求分配器。您可以改用持久分配(通过使用较低级别的 zend_hash 和 zend_string API 并传递 persistent=1 标志),但仍然不允许您从 PHP 函数返回这样的数组,因为这违反了 PHP 内存模型(不允许在请求期间更改持久值的引用计数)。如果你想使用 per-request 分配器在全局中放置一个值,你需要在 RINIT 中这样做(然后在 RSHUTDOWN 中销毁)。这些处理程序作为每个请求的一部分被调用。尽管对于您的特定用例,我建议根本不使用全局变量,而是在每次调用函数时重新构造数组。它不是性能关键的。
打开App,查看更多内容
随时随地看视频慕课网APP