<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>风雪之隅 &#187; php bug</title>
	<atom:link href="http://www.laruence.com/tag/php-bug/feed" rel="self" type="application/rss+xml" />
	<link>http://www.laruence.com</link>
	<description>PHP语言, PHP扩展, Zend引擎相关的研究,技术,新闻分享 - 左手代码 右手诗</description>
	<lastBuildDate>Wed, 08 Feb 2012 05:12:49 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.1.2</generator>
		<item>
		<title>PHP5.2.x + APC的一个bug的定位</title>
		<link>http://www.laruence.com/2009/12/05/1172.html</link>
		<comments>http://www.laruence.com/2009/12/05/1172.html#comments</comments>
		<pubDate>Sat, 05 Dec 2009 07:39:24 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[apc]]></category>
		<category><![CDATA[bug]]></category>
		<category><![CDATA[core]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[php bug]]></category>
		<category><![CDATA[session]]></category>
		<category><![CDATA[spl_autoload]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1172</guid>
		<description><![CDATA[昨天环境迁移, 脚本出core, 因为之前的环境上运行正常, 所以初步认为是环境问题. 通过对core文件的分析, 初步发现原因和spl_autoload相关, backtrace如下:
<coolcode lang="bash" linenum="off">
#0  zif_spl_autoload (ht=Variable "ht" is not available.)
at /home/huixinchen/package/php-5.2.11/ext/spl/php_spl.c:310
310   if (active_opline->opcode != ZEND_FETCH_CLASS) {

(gdb) bt
#0  zif_spl_autoload (ht=Variable "ht" is not available.
	) at /home/huixinchen/package/php-5.2.11/ext/spl/php_spl.c:310
#1  0x00000000006a5da5 in zend_call_function (fci=0x7fbfffc100, 
		fci_cache=Variable "fci_cache" is not available.)
at /home/huixinchen/package/php-5.2.11/Zend/zend_execute_API.c:1052
.....
</coolcode>
脚本很简单, 通过session_set_save_handler注册了一个类为session的user handler.

去掉spl_autoload以后,  不出core了, 但是每次都会抛出Class not found的异常, 可见core确实和spl_autoload有关, 但是这个Class ** not found的fatal error问题又和什么相关呢, 这个fatal error是否是导致spl_autoload core 的直接原因呢?

代码本身并没有任何问题, 对环境做了对比以后, 初步认定为新环境启用了APC的缘故.

在bug.php中找到了有人报告类似的bug(<a href="http://bugs.php.net/bug.php?id=49867&#038;edit=2" target="_blank">spl_autoload crashes when called in write function of custom sessionSaveHandler</a>), 但没有任何一个人给出原因,或者解决的办法. 

看来, 只能自己分析了....]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: <a href="http://www.laruence.com" >Laruence</a>(<a href="http://www.twitter.com/laruence"  target="meme"  title="Twitter" ><img src="/images/ico-twitter.png" /></a> <a href="http://t.sina.com/laruence"  target="meme"  title="新浪微博" ><img src="/images/ico-sina.png" /></a> <a href="http://fusion.google.com/add?feedurl=http://www.laruence.com/feed"  target="meme"  title="Google阅读器" ><img src="/images/ico-google.png" /></a> <a href="mailto:laruence@yahoo.com.cn"  target="meme"  title="邮件" ><img src="/images/ico-mail.png" /></a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2009/12/05/1172.html"  title="Permanet Link to PHP5.2.x + APC的一个bug的定位" >http://www.laruence.com/2009/12/05/1172.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>
昨天环境迁移, 脚本出core, 因为之前的环境上运行正常, 所以初步认为是环境问题. 通过对core文件的分析, 初步发现原因和spl_autoload相关, backtrace如下:</p>
<pre name="code"  class="sh_bash"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
#0  zif_spl_autoload (ht=Variable &quot;ht&quot; is not available.)
at /home/huixinchen/package/php-5.2.11/ext/spl/php_spl.c:310
310   if (active_opline-&gt;opcode != ZEND_FETCH_CLASS) {

(gdb) bt
#0  zif_spl_autoload (ht=Variable &quot;ht&quot; is not available.
	) at /home/huixinchen/package/php-5.2.11/ext/spl/php_spl.c:310
#1  0x00000000006a5da5 in zend_call_function (fci=0x7fbfffc100,
		fci_cache=Variable &quot;fci_cache&quot; is not available.)
at /home/huixinchen/package/php-5.2.11/Zend/zend_execute_API.c:1052
.....
</pre>
<p>脚本很简单, 通过session_set_save_handler注册了一个类为session的user handler.</p>
<p>去掉spl_autoload以后,  不出core了, 但是每次都会抛出Class not found的异常, 可见core确实和spl_autoload有关, 但是这个Class ** not found的fatal error问题又和什么相关呢, 这个fatal error是否是导致spl_autoload core 的直接原因呢?</p>
<p>代码本身并没有任何问题, 对环境做了对比以后, 初步认定为新环境启用了APC的缘故.</p>
<p>在bug.php中找到了有人报告类似的bug(<a href="http://bugs.php.net/bug.php?id=49867&#038;edit=2"  target="_blank" >spl_autoload crashes when called in write function of custom sessionSaveHandler</a>), 但没有任何一个人给出原因,或者解决的办法. </p>
<p>看来, 只能自己分析了&#8230;.
</p>
<p>
精简的代码如下:</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
&lt;?php
/**
 * PHP5.2.11 with APC Fatal Error example
 * by laruence(http://www.laruence.com)
 */
class Laruence {
	public static function start() {
		session_set_save_handler(array(__CLASS__, &quot;open&quot;),
				array(__CLASS__, &quot;close&quot;), array(__CLASS__, &quot;read&quot;),
				array(__CLASS__, &quot;write&quot;), array(__CLASS__, &quot;destroy&quot;),
				array(__CLASS__, &quot;gc&quot;));
		session_start();
	}
	public static function open($strPath, $strSessName) {
		return true;
	}
	public static function close() {
		var_dump(class_exists(__CLASS__, false));
	}
	public static function read($strSessId) {
	}
	public static function write($strSessId, $strData) {
	}
	public static function destroy($strSessId) {
	}
	public static function gc($intMaxLifeTime) {
		return true;
	}
}
Laruence::start();
?&gt;
</pre>
<p>当第一次请求这个页面的时候, 一切正常, 当再次请求的时候, 就会产生:</p>
<pre name="code"  class="sh_php"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
PHP Fatal error:  Class 'Laruence' not found in Unknown on line 0
</pre>
<p>可见, 这个原因一定是和APC缓存了脚本编译结果以后有关.</p>
<p>翻看APC的源码, 发现了一处可怀疑之处, apc_main.c中:</p>
<pre name="code"  class="sh_cpp"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
static void apc_deactivate(TSRMLS_D) //此函数在请求关闭期间被调用
{
while (apc_stack_size(APCG(cache_stack)) &gt; 0) {
...//有省略
	if (cache_entry-&gt;data.file.classes) {
		for (i = 0; cache_entry-&gt;data.file.classes[i].class_entry != NULL; i++) {
			if(zend_hash_find(EG(class_table),
					cache_entry-&gt;data.file.classes[i].name,
					cache_entry-&gt;data.file.classes[i].name_len+1,
					(void**)centry) == FAILURE) {
						continue;
			}
			//注意这里:
			zend_hash_del(EG(class_table),
					cache_entry-&gt;data.file.classes[i].name,
					cache_entry-&gt;data.file.classes[i].name_len+1);
			apc_free_class_entry_after_execution(zce);
		}
	}

	...//有省略
}
}
</pre>
<p>也就是说, APC在模块请求关闭函数时期, 清空了执行全局标量中的类定义表EG(classs_table), 根据我的经验, 问题可能就在这里.</p>
<p>经过反复验证: 改hanlder,  跟踪源码, gdb,, 最后问题定位确定, 确实就是这个原因(对不住女朋友了, 搞到半夜快2点才最终确定问题):</p>
<p>恩, 我之前的文章介绍过PHP的扩展载入过程(<a href="http://www.laruence.com/2009/06/14/945.html"  target="_blank" >深入理解PHP原理之扩展载入过程</a>), 但没有涉及到模块关闭过程.</p>
<p>而这个问题就和模块载入顺序和模块关闭函数很有关系了. 总体来说, 就是PHP会根据模块载入的顺序的反序来在每次请求处理结束后依次调用各个扩展的请求关闭函数.</p>
<p>因为我们环境的Session是静态编译进PHP的, 所以Session模块一定先于动态编译进PHP的APC被载入, 也就是说, 在请求关闭时期, APC的请求关闭函数, 一定会先于Session的请求关闭函数被调用.</p>
<p>所以,当Session的请求关闭函数调用的时候, 执行环境的Class Table已经为空, 当然也就会抛出类找不到的fatalerror了.</p>
<p>而, 第一次请求的时候, 因为页面没有被缓存, 所以apc_stack_size(APCG(cache_stack))的条件判断不成立, 也就不会有清除class table的动作发生.</p>
<p>基于此, 为什么在spl_autoload启用以后, 产生core, 也就很明显了.</p>
<p>因为在zif_spl_autoload中, 对active_opline接引用, 而此时执行已经结束, active_opline为空, 所以,segment fault了.</p>
<p>那么, 如何解决这个问题呢?</p>
<pre name="code"  class="sh_sh"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
1. 关闭APC //废话,我也知道, 呵呵
2. 改用函数做为session_set_save_handler的user handler.
3. 把seesion模块做为动态模块载入PHP, 并保证它后于APC被载入. //这个解决方法靠谱.
</pre>
<p>关于APC的执行原理, 大家如果有兴趣, 我过段再单独写篇blog.</p>
<p>最后, APC是好, 但一致没有被做为PHP的标准扩展, 也是有原因的. 它劫持了PHP自身的complie_file, 加入了很多局部性很强的逻辑&#8230;</p>
<p>一句话, APC虽好, 但须慎用.</p>
<p><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_bash.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_php.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_cpp.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_sh.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2009/12/06</a>, 玉丰 writes: 最近也在折腾gdb，看了一下这篇文章，（还不会如何去backtrace PHP的运行），呵呵，继续学习。</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2009/12/07</a>, <a href="www.phppan.com"  rel="external nofollow"  class="url" >phppan</a> writes: 围观，学习！</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2009/12/16</a>, kimjxie writes: 在代码末 强制执行session_write_close()也可解决问题</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2009/12/17</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @kimjxie 赞~, 这是提前了关闭的时机. 这个bug还是依然值得探讨的. ;)</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2010/01/15</a>, <a href="http://www.baidu.com"  rel="external nofollow"  class="url" >wakaka</a> writes: 博主的PHP和C的功力实在是国内少有的高手。</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2010/03/19</a>, luckgo writes: 老兄，我遇到类似问题，但无法解决。
我在windows下装了php_apc.dll后，访问phpMyAdmin（版本3.1.3）出现错误：
Warning: require_once(D:\apache\libraries\common.inc.php) [function.require-once]: failed to open stream: No such file or directory in E:\phpweb\phpMyAdmin3\index.php  on line 34

在使用zend framework框架时，出现
class XXX not found的错误，很奇怪，似乎与session没什么关系，请问有没办法解决？</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2010/03/20</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @luckgo 文件不存在那么..</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2010/07/28</a>, abagail writes: Zenith Watches Company is a Swiss company that has <a href="http://www.sanwatches.com/cartier-watches.html"  rel="nofollow" >cartier fake watches</a> breitling chronomat evolution straps have the advantage of being made from a <a href="http://www.sanwatches.com/a_lange_and_sohne-watches.html"  rel="nofollow" >replica a lange and sohne watch</a> automatic watches far from what they like or would buy for <a href="http://www.watchesfaner.com/swiss_rolex-watches.html"  rel="nofollow" >swiss replica</a> assioma watches available on the new RSW High King Tourbillon <a href="http://www.watchesfaner.com/ladies_watches.html"  rel="nofollow" >buy watches</a> omega olympic collection watches enhanced and the promotional lights create an <a href="http://www.corwatches.org/"  rel="nofollow" >replica watches</a> retailers to see what products have arrived in <a href="http://www.corwatches.org/rolex-milgauss-watches.html"  rel="nofollow" >rolex milgauss watches</a> arrives with a long lasting brass situation Other <a href="http://www.sanwatches.com/tag_heuer-watches.html"  rel="nofollow" >tag heuer fake</a> heard about Gucci They are one of the largest <a href="http://www.sanwatches.com/"  rel="nofollow" >fake watch</a> that updated to make it more suitable to the <a href="http://www.pocwatches.com/"  rel="nofollow" >replica watch</a> out with various styles celebrating this trip to <a href="http://www.sanwatches.com/"  rel="nofollow" >watches replica</a> baguette cut diamonds and baguette cut rubies <a href="http://www.sanwatches.com/breitling-watches.html"  rel="nofollow" >breitling fake watches</a> libre watches a team of visionary designers and specialists of <a href="http://www.watchesfaner.com/omega-watches.html"  rel="nofollow" >replica omega</a> under their French cuff shirts and hence they can</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2010/08/19</a>, <a href="http://www.watchfordream.com"  rel="external nofollow"  class="url" >Watchfordream</a> writes: Wonderful!
<a href="http://wwww.watchfordream.com"  rel="nofollow" >swiss replica watches</a></li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2011/01/20</a>, <a href="http://zhg.me"  rel="external nofollow"  class="url" >hfcorriez</a> writes: 受教了。</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2011/03/20</a>, <a href="http://www.w3hacker.com/?p=172"  rel="external nofollow"  class="url" >PHP5.2.x + APC的一个bug的定位 | 万维网黑客联盟</a> writes: [...] 本文地址: http://www.laruence.com/2009/12/05/1172.html [...]</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2011/09/26</a>, <a href="http://blog.iterse.com"  rel="external nofollow"  class="url" >iterse's blog</a> writes: 恩，学习了。前几天遇到了这个问题，谢谢分享！</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2011/12/06</a>, hfcorriez writes: 以前也发现过这个问题，苦于自己没法定位放弃APC了。今天终于知道原因了。</li><li><a href="http://www.laruence.com/2009/12/05/1172.html" >2012/01/12</a>, 偷蚊子的 writes: 新人，来报道～</li></ul><hr/><h2>Related posts:</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2009/11/27/1164.html"  rel="bookmark"  title="Permanent Link: memory_limit的一个bug" >memory_limit的一个bug</a></li><li><a href="http://www.laruence.com/2011/03/22/1929.html"  rel="bookmark"  title="Permanent Link: PHP Reflection Extension的一个bug" >PHP Reflection Extension的一个bug</a></li><li><a href="http://www.laruence.com/2010/05/26/1541.html"  rel="bookmark"  title="Permanent Link: PHP类型转换相关的一个Bug" >PHP类型转换相关的一个Bug</a></li></ul><hr/><small  style="font-size:85%;font-size:85%;">Copyright &copy; 2010 <a href="http://www.laruence.com"  target="_blank" >风雪之隅</a> 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)</small><h2 class="related_post_title" >Related Posts:</h2><ul class="related_post"   style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2012/01/10/2469.html"  title="如何设置一个严格30分钟过期的Session" >如何设置一个严格30分钟过期的Session</a></li><li><a href="http://www.laruence.com/2011/12/06/2381.html"  title="更简单的重现PHP Core的调用栈" >更简单的重现PHP Core的调用栈</a></li><li><a href="http://www.laruence.com/2011/10/10/2217.html"  title="上传进度支持(Upload progress in sessions)" >上传进度支持(Upload progress in sessions)</a></li><li><a href="http://www.laruence.com/2011/06/23/2057.html"  title="如何调试PHP的Core之获取基本信息" >如何调试PHP的Core之获取基本信息</a></li><li><a href="http://www.laruence.com/2011/03/29/1949.html"  title="深入理解PHP原理之Session Gc的一个小概率Notice" >深入理解PHP原理之Session Gc的一个小概率Notice</a></li><li><a href="http://www.laruence.com/2011/03/22/1929.html"  title="PHP Reflection Extension的一个bug" >PHP Reflection Extension的一个bug</a></li><li><a href="http://www.laruence.com/2011/01/27/1854.html"  title="深入理解PHP内存管理之一个低概率Core的分析" >深入理解PHP内存管理之一个低概率Core的分析</a></li><li><a href="http://www.laruence.com/2010/09/27/1754.html"  title="PHP stream未能及时清理现场导致Core的bug" >PHP stream未能及时清理现场导致Core的bug</a></li><li><a href="http://www.laruence.com/2010/05/28/1565.html"  title="PHP错误抑制符(@)导致引用传参失败的Bug" >PHP错误抑制符(@)导致引用传参失败的Bug</a></li><li><a href="http://www.laruence.com/2010/05/26/1541.html"  title="PHP类型转换相关的一个Bug" >PHP类型转换相关的一个Bug</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2009/12/05/1172.html/feed</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>memory_limit的一个bug</title>
		<link>http://www.laruence.com/2009/11/27/1164.html</link>
		<comments>http://www.laruence.com/2009/11/27/1164.html#comments</comments>
		<pubDate>Fri, 27 Nov 2009 09:40:02 +0000</pubDate>
		<dc:creator>雪候鸟</dc:creator>
				<category><![CDATA[PHP源码分析]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[php bug]]></category>
		<category><![CDATA[php源码分析]]></category>

		<guid isPermaLink="false">http://www.laruence.com/?p=1164</guid>
		<description><![CDATA[<p>
		PHP 5.2x中, 由于错误的选用了zend_atoi, 导致memory_limit不能设置为超过4G的值.

	今天同事分享给我一个问题(thans to yanmi), 一段代码(PHP 5.2.11 Linux/X86_64),设置memory_limit为4096M会导致内存耗尽, 而设置4095M就不会.  奇怪的问题呵.

	那是怎么回事呢?
</p>]]></description>
			<content:encoded><![CDATA[<div class="copyright" >
<ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;">
<li>作者: <a href="http://www.laruence.com" >Laruence</a>(<a href="http://www.twitter.com/laruence"  target="meme"  title="Twitter" ><img src="/images/ico-twitter.png" /></a> <a href="http://t.sina.com/laruence"  target="meme"  title="新浪微博" ><img src="/images/ico-sina.png" /></a> <a href="http://fusion.google.com/add?feedurl=http://www.laruence.com/feed"  target="meme"  title="Google阅读器" ><img src="/images/ico-google.png" /></a> <a href="mailto:laruence@yahoo.com.cn"  target="meme"  title="邮件" ><img src="/images/ico-mail.png" /></a>)</li>
<li>本文地址: <a href="http://www.laruence.com/2009/11/27/1164.html"  title="Permanet Link to memory_limit的一个bug" >http://www.laruence.com/2009/11/27/1164.html</a></li>
</li>
<li>转载请注明出处 </li>
</ul></div>
<p>
	PHP 5.2x中, 由于错误的选用了zend_atoi, 导致memory_limit不能设置为超过4G的值.</p>
<p>	今天同事分享给我一个问题(thans to yanmi), 一段代码(PHP 5.2.11 Linux/X86_64),设置memory_limit为4096M会导致内存耗尽, 而设置4095M就不会.  奇怪的问题呵.</p>
<p>	那是怎么回事呢?
</p>
<p>	问题的原因也很简单, 在PHPSRC/main.c中定义的memory_limit设置项的处理器OnChangeMemoryLimit中, 并没有检测当前的机器字长, 而统一使用了zend_atoi来做为字符串数字化, 这个问题在PHP5.3的版本中已经修正(换成了zend_atol):</p>
<pre name="code"  class="sh_c"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
static PHP_INI_MH(OnChangeMemoryLimit)
{
    if (new_value) {
        PG(memory_limit) = zend_atoi(new_value, new_value_length);
    } else {
        PG(memory_limit) = 1&lt;&lt;30;       /* effectively, no limit */
    }
    return zend_set_memory_limit(PG(memory_limit));
}
</pre>
<p>	而, 顾名思义么, atoi是转成整形, 4096M是2的32次方, 发生溢出, 继而环绕成结果为0, zend_atoi代码如下:</p>
<pre name="code"  class="sh_c"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
ZEND_API int zend_atoi(const char *str, int str_len)
{
    int retval;

    if (!str_len) {
        str_len = strlen(str);
    }
    retval = strtol(str, NULL, 0);
    if (str_len&gt;0) {
        switch (str[str_len-1]) {
            case 'g':
            case 'G':
                retval *= 1024;
                /* break intentionally missing */
            case 'm':
            case 'M':
                retval *= 1024;
                /* break intentionally missing */
            case 'k':
            case 'K':
                retval *= 1024;
                break;
        }
    }
    return retval;
}
</pre>
<p>最后在zend_set_memory_limit的时候, 会错误的设置memory_limit为mm_heap的blok_size, 那结果就肯定远远小与你所预期的4096M了</p>
<pre name="code"  class="sh_c"  linenum="off"   style="background: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:Monacobackground: #333; color: #d9d9d9; border-left: 15px solid #c9c9c9; padding: 9px; font-size: 1em; overflow-x: auto;font-family:MonacoConsolasConsolasCourierCouriermonospace;monospace;">
....
 AG(mm_heap)-&gt;limit = (memory_limit &gt;= AG(mm_heap)-&gt;block_size) ? memory_limit : AG(mm_heap)-&gt;block_size;
...
</pre>
<p>最后, 如果是32位的机器,  那确实不算bug,  但现在的机器很多都64了, 最大内存也不再是4GB了, PHP也要与时俱进啊.</p>
<p>PS, 多看别人的代码是有好处的, 今天有学会了intentionally这个单词, ^_^.<br/>
<script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_c.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_c.js" ></script><script type="text/javascript"  src="http://www.laruence.com/wp-content/plugins/shjs-syntax-hiliter/shjs/lang/sh_c.js" ></script></p>
<hr/><h2>Comments</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2009/11/27/1164.html" >2009/11/27</a>, <a href="http://onemouse.cn"  rel="external nofollow"  class="url" >Anders</a> writes: 真的使用了4G内存？

那我们这些开发机只有512M内存的人怎么活啊?</li><li><a href="http://www.laruence.com/2009/11/27/1164.html" >2009/11/27</a>, <a href="http://www.laruence.com"  rel="external nofollow"  class="url" >雪候鸟</a> writes: @Anders 呵呵, 现在的服务器都不止4G的内存了..., 不过这个bug确实影响不大..</li><li><a href="http://www.laruence.com/2009/11/27/1164.html" >2009/11/27</a>, fortruth writes: 果然， 今天我也学到了 intentionally 这个单词。 :)</li><li><a href="http://www.laruence.com/2009/11/27/1164.html" >2009/11/27</a>, kevin writes: 4个G内存消耗确实不常见，但有时需要遍历一些数据库操作大数据集的时候还是比较容易碰到的。

分析的不错！另：1&lt;&lt;30是多大？</li><li><a href="http://www.laruence.com/2009/11/27/1164.html" >2009/11/27</a>, kevin writes: 另：1&lt;&lt;30是多大？

--------------------------

应该是pow(2,30)吧,2的30次方。</li><li><a href="http://www.laruence.com/2009/11/27/1164.html" >2009/11/29</a>, <a href="http://www.xklog.org"  rel="external nofollow"  class="url" >星空泪</a> writes: 占用 4G 内存的程序大概需要优化了……</li><li><a href="http://www.laruence.com/2009/11/27/1164.html" >2009/12/02</a>, Anonymous writes: 脚本语言估计是不会 要 4G 内存的了。</li><li><a href="http://www.laruence.com/2009/11/27/1164.html" >2009/12/02</a>, laruence writes: @Anonymous 恩, 这个只是就问题而说问题, 再说,设置成4096,不代表就要用4096么, ;_)</li></ul><hr/><h2>Related posts:</h2><ul  style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2010/04/13/1408.html"  rel="bookmark"  title="Permanent Link: ini_set memory_limit在safe_mode下不可用" >ini_set memory_limit在safe_mode下不可用</a></li><li><a href="http://www.laruence.com/2011/03/22/1929.html"  rel="bookmark"  title="Permanent Link: PHP Reflection Extension的一个bug" >PHP Reflection Extension的一个bug</a></li><li><a href="http://www.laruence.com/2010/05/26/1541.html"  rel="bookmark"  title="Permanent Link: PHP类型转换相关的一个Bug" >PHP类型转换相关的一个Bug</a></li><li><a href="http://www.laruence.com/2009/12/05/1172.html"  rel="bookmark"  title="Permanent Link: PHP5.2.x + APC的一个bug的定位" >PHP5.2.x + APC的一个bug的定位</a></li></ul><hr/><small  style="font-size:85%;font-size:85%;">Copyright &copy; 2010 <a href="http://www.laruence.com"  target="_blank" >风雪之隅</a> 版权所有, 转载务必注明. 该Feed只供个人使用, 禁止未注明的转载或商业应用. 非法应用的, 一切法律后果自负. 如有问题, 可发E-mail至my at laruence.com.(Digital Fingerprint: 73540ba0a1738d7d07d4b6038d5615e2)</small><h2 class="related_post_title" >Related Posts:</h2><ul class="related_post"   style="padding-left:1em;font-size:85%;padding-left:1em;font-size:85%;"><li><a href="http://www.laruence.com/2011/03/04/1894.html"  title="深入理解PHP内存管理之谁动了我的内存" >深入理解PHP内存管理之谁动了我的内存</a></li><li><a href="http://www.laruence.com/2010/05/26/1541.html"  title="PHP类型转换相关的一个Bug" >PHP类型转换相关的一个Bug</a></li><li><a href="http://www.laruence.com/2010/05/20/1495.html"  title="Nginx + PHP CGI的一个可能的安全漏洞" >Nginx + PHP CGI的一个可能的安全漏洞</a></li><li><a href="http://www.laruence.com/2010/05/18/1482.html"  title="深入理解PHP原理之对象(一)" >深入理解PHP原理之对象(一)</a></li><li><a href="http://www.laruence.com/2009/12/05/1172.html"  title="PHP5.2.x + APC的一个bug的定位" >PHP5.2.x + APC的一个bug的定位</a></li><li><a href="http://www.laruence.com/2009/10/15/1131.html"  title="提升PHP性能之改变Zend引擎分发方式" >提升PHP性能之改变Zend引擎分发方式</a></li><li><a href="http://www.laruence.com/2009/09/26/1103.html"  title="PHP文件上传源码分析(RFC1867)" >PHP文件上传源码分析(RFC1867)</a></li><li><a href="http://www.laruence.com/2009/07/27/1020.html"  title="深入理解PHP原理之错误抑制与内嵌HTML" >深入理解PHP原理之错误抑制与内嵌HTML</a></li><li><a href="http://www.laruence.com/2012/02/08/2528.html"  title="PHP-5.3.9远程执行任意代码漏洞(CVE-2012-0830)" >PHP-5.3.9远程执行任意代码漏洞(CVE-2012-0830)</a></li><li><a href="http://www.laruence.com/2012/02/02/2515.html"  title="我们什么时候应该使用异常?" >我们什么时候应该使用异常?</a></li></ul>]]></content:encoded>
			<wfw:commentRss>http://www.laruence.com/2009/11/27/1164.html/feed</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
	</channel>
</rss>

