php错误级别:2

tech2022-09-06  102

php错误级别:2

Previously, we covered contributing to PHP’s documentation. Now, we will be covering how to get involved with PHP’s core. To do this, we will be looking at the workflow for fixing a simple bug in the core.

之前,我们介绍了对PHP文档的贡献。 现在,我们将介绍如何参与PHP的核心。 为此,我们将研究在内核中修复简单错误的工作流程。

Since submitting new features to PHP has already been explained pretty well, we will not be covering that here. Also, this article does not seek to teach PHP’s internals. For more information on that, please see my previous posts on adding features to PHP.

由于已经向PHP 很好地解释了向PHP提交新功能的过程,因此在此不再赘述。 另外,本文也不打算讲授PHP的内部原理。 有关这方面的更多信息,请参阅我以前有关向PHP添加功能的文章 。

解决错误 (Resolving Bugs)

Fixing bugs in the core is a great way to gain a basic familiarity with PHP’s internals. It only requires a basic knowledge of C and is an easy way to help with the effort of improving PHP. But before doing so, a basic familiarity is required with PHP’s version management.

修复内核中的错误是对PHP内部基本了解的一种好方法。 它只需要C的基础知识,并且是帮助改进PHP的简便方法。 但是在这样做之前,需要对PHP的版本管理有基本的了解。

PHP版本管理生命周期 (PHP Version Management Lifecycle)

PHP minor versions follow a yearly release cycle, and each minor version has 3 years of support. The first 2 years provide “active support” for general bug fixes, and the final year provides “security support” for security fixes only. After the 3 year cycle has ended, support for that PHP version is dropped.

PHP次要版本遵循每年的发布周期,每个次要版本均具有3年的支持。 前两年为常规错误修复提供“主动支持”,而最后一年仅为安全修复提供“安全支持”。 3年的周期结束后,将不再支持该PHP版本。

The currently supported PHP versions can be seen on the php.net website. At the time of writing, PHP 5.5 is in security support, and PHP 5.6 and 7 are in active support.

当前支持PHP版本可以在php.net网站上看到。 在撰写本文时,PHP 5.5具有安全性支持,而PHP 5.6和7具有积极性支持。

修正错误 (Fixing a Bug)

To demonstrate a basic workflow, let’s resolve bug #71635 from bugs.php.net. The bug report states that there is a segfault when invoking DatePeriod::getEndDate() when no end date is available. So the first thing we will want to do is confirm its validity.

为了演示基本的工作流程,让我们从bugs.php.net解决bug# 71635 。 错误报告指出,当没有结束日期可用时,调用DatePeriod::getEndDate()时存在段错误。 因此,我们要做的第一件事就是确认其有效性。

For bugs that look trivial (with little or no environmental setup requirements), we can begin by quickly seeing if the bug can be reproduced in 3v4l. (3v4l is a handy tool that runs a snippet of code on hundreds of PHP versions.) This allows us to see all of the affected PHP versions, which is handy to quickly find out if older, still supported versions of PHP are affected. As we can see, PHP exits with a segfault for all versions 5.6.5 through to 7.0.4.

对于看似微不足道的bug(几乎没有环境设置要求),我们可以从快速查看bug是否可以在3v4l中复制开始 。 (3v4l是一个方便的工具,可以在数百个PHP版本上运行一小段代码。)这使我们可以查看所有受影响PHP版本,从而可以方便地快速找出是否仍旧受支持PHP版本受到影响。 如我们所见,对于所有版本5.6.5到7.0.4,PHP都退出并带有段错误。

Regardless of whether the bug can be replicated in 3v4l or not, we’re going to need to replicate it locally before we can go about fixing it. For this, you’ll need to fork php/php-src and clone your fork locally. If you already did this some time ago, you may need to update your clone, along with retrieving all of the latest tagged releases (with git remote update).

无论该错误是否可以在3v4l中复制,我们都需要在本地对其进行复制,然后才能对其进行修复。 为此,您需要派生php / php-src并在本地克隆您的派生。 如果您之前已经这样做,则可能需要更新克隆,并检索所有最新的标记发行版(使用git remote update )。

We’re going to work on the PHP 5.6 branch since that’s the lowest version of PHP affected by this bug (whilst still being actively supported). (Had this bug affected PHP 5.5, we would still ignore this version and work against PHP 5.6 due to this bug not being security related.) The standard workflow for submitting bug fixes is to target the fix to the lowest affected (whilst still supported) PHP version. One of the php/php-src developers will then merge the fix upwards as necessary.

我们将在PHP 5.6分支上工作,因为这是受此错误影响的最低PHP版本(尽管仍在积极支持中)。 (如果此错误影响PHP 5.5,由于此错误与安全无关,我们仍将忽略此版本,并针对PHP 5.6进行工作。)提交错误修复的标准工作流程是将修复定向到受影响最低的位置(仍受支持) PHP版本。 然后,其中一名php / php-src开发人员将根据需要向上合并此修复程序。

So let’s checkout a copy of the PHP 5.6 branch to work in:

因此,让我们签出一个PHP 5.6分支的副本以进行工作:

git checkout -b fix-dateperiod-segfault upstream/php-5.6

We then build PHP and attempt to reproduce the segfault locally by creating a file (say segfault.php) with the following code:

然后,我们构建PHP并尝试通过使用以下代码创建文件(例如segfault.php )在本地重现segfault:

<?php $period = new DatePeriod(new DateTimeImmutable("now"), new DateInterval("P2Y4DT6H8M"), 2); var_dump($period->getEndDate());

We then run segfault.php with the freshly built PHP binary:

然后,我们使用新构建PHP二进制文件运行segfault.php :

sapi/cli/php -n segfault.php

(The -n flag means that a php.ini file will not be used for configuration. This is particularly handy to use if you have custom extensions loaded into your default php.ini file, since it will prevent a load of errors from popping up each time you execute a file with a local PHP binary.)

( -n标志表示将不会使用php.ini文件进行配置。如果您将自定义扩展名加载到默认php.ini文件中,则此操作特别方便,因为它将防止弹出大量错误信息每次您使用本地PHP二进制文件执行文件时。)

Once confirmed that we can trigger this locally, we can then create a test for it. Let’s call this test file bug71635.phpt and place it in the ext/date/tests/ folder with the following contents:

一旦确认我们可以在本地触发,就可以为其创建测试。 让我们将此测试文件称为bug71635.phpt并将其放置在ext / date / tests /文件夹中,其中包含以下内容:

--TEST-- Bug #71635 (segfault in DatePeriod::getEndDate() when no end date has been set) --FILE-- <?php date_default_timezone_set('UTC'); $period = new DatePeriod(new DateTimeImmutable("now"), new DateInterval("P2Y4DT6H8M"), 2); var_dump($period->getEndDate()); ?> --EXPECT-- NULL

Running that single test shows that it does not pass:

运行该单个测试表明它没有通过:

make test TESTS=ext/date/tests/bug71635.phpt

We now run a debugger of our choice on the segfault.php file that we created earlier. (I use LLDB because that’s what Mac OS X bundles with now, but GDB is another similar debugger that has overlapping commands.)

现在,我们在之前创建的segfault.php文件上运行我们选择的调试器。 (我使用LLDB,因为这是Mac OS X现在捆绑的,但是GDB是另一个类似的调试器,具有重叠的命令 。)

lldb sapi/cli/php a.php

(The -n command has not been used this time, since it seems to mess with lldb.)

(这一次没有使用-n命令,因为它似乎与lldb混淆了。)

Now we’re in the LLDB debugger, we type run to execute the file. It should show where in the code the segfault occurred:

现在我们在LLDB调试器中,键入run以执行文件。 它应该显示段在代码中发生的位置:

Whilst the first frame doesn’t seem to show us anything overly meaningful (unless you program in asm), we can see that the program stopped because of an EXC_BAD_ACCESS. It also showed us that the pointer address it attempted to manipulate was 0x0, so we can see that we have a null pointer access.

虽然第一帧似乎没有向我们显示任何过分有意义的内容(除非您使用asm编程),但我们可以看到该程序由于EXC_BAD_ACCESS停止了。 它还向我们展示了它尝试操作的指针地址为0x0 ,因此我们可以看到我们具有空指针访问权限。

Using the bt command shows us the backtrace of the segfault (every frame leading up to the segfault). Looking at frame #1 (by entering frame select 1), we are back into C code and can see the line causing the problem:

使用bt命令可以向我们显示段错误的回溯(每个导致段错误的帧)。 查看第1帧(通过输入frame select 1 ),我们回到C代码中,可以看到导致问题的行:

From this, we can infer that the culprit is dpobj->end evaluating to null, and thus attempting to dereference it causes the segfault. So, we place a check above this to see if dpobj->end is a null pointer, and if so, simply return from the function (doing this as early as possible):

由此,我们可以推断出罪魁祸首是dpobj->end评估为null,因此尝试对其取消引用会导致段错误。 因此,我们在此上方进行检查以查看dpobj->end是否为空指针,如果是,则只需从函数中返回即可(尽早执行此操作):

PHP_METHOD(DatePeriod, getEndDate) { php_period_obj *dpobj; php_date_obj *dateobj; if (zend_parse_parameters_none() == FAILURE) { return; } dpobj = (php_period_obj *)zend_object_store_get_object(getThis() TSRMLS_CC); + + if (!dpobj->end) { + return; + } php_date_instantiate(dpobj->start_ce, return_value TSRMLS_CC); dateobj = (php_date_obj *)zend_object_store_get_object(return_value TSRMLS_CC); dateobj->time = timelib_time_ctor(); *dateobj->time = *dpobj->end; if (dpobj->end->tz_abbr) { dateobj->time->tz_abbr = strdup(dpobj->end->tz_abbr); } if (dpobj->end->tz_info) { dateobj->time->tz_info = dpobj->end->tz_info; } }

(Returning from a method implicitly makes the function return null (as all internal PHP functions do on failure). This is because the return_value variable (which is accessible in any function definition) holds the function’s actual return value, and it defaults to null.)

(从方法中隐式返回使函数返回null (就像所有内部PHP函数在失败时一样)。这是因为return_value变量(在任何函数定义中都可以访问)保存了函数的实际返回值,并且默认为null。 )

So let’s build PHP and run our test again:

因此,让我们构建PHP并再次运行测试:

make test TESTS=ext/date/tests/bug71635.phpt

It should now pass! Now we can simply commit the updated file and the corresponding bug test, and then submit a PR against the 5.6 branch of php/php-src.

现在应该过去了! 现在,我们只需提交更新的文件和相应的错误测试,然后针对php / php-src的5.6分支提交PR 。

结论 (Conclusion)

This article has demonstrated a simple workflow used when resolving bugs in the core. Solving bugs is a great starting point to getting involved with PHP’s internals, and it requires very little knowledge of C.

本文演示了解决核心错误时使用的简单工作流程。 解决错误是参与PHP内部知识的一个很好的起点,并且它几乎不需要C知识。

Bug fixing also serves as a nice series of small programming challenges for those who are bored of the algorithmic-based challenges found at Project Euler and similar websites. And with over 5,000 open bug reports, there’s certainly no shortage of bugs to tackle!

对于那些对在Euler项目和类似网站中发现的基于算法的挑战感到厌倦的人来说,错误修复还可以作为一系列不错的小型编程挑战。 凭借5,000多个未解决的错误报告 ,肯定不乏需要解决的错误!

翻译自: https://www.sitepoint.com/contributing-to-php-how-to-fix-bugs-in-the-php-core/

php错误级别:2

相关资源:jdk-8u281-windows-x64.exe
最新回复(0)