PHP: Fix bug PHP Core
Trang 1 trong tổng số 1 trang • Share
- DenDenMuShiThành viên mới
- Tổng số bài gửi : 10
Điểm : 30
Danh vọng : 0
Ngày tham gia : 10/03/2018
Hôm nay, chúng ta sẽ tìm hiểu về PHP Core. Trước đó, ta sẽ xem xét workflow cho một bug đơn giản trong core.
Mục đích của bài viết này không phải để dạy các bạn cách thêm tính năng mới vào PHP. Nếu bạn muốn tìm hiểu thêm về vấn đề này, bạn có thể đọc thêm bài viết này..
Sửa lỗi
Sửa lỗi trong core (chỉ yêu cầu bạn biết C cơ bản) là một cách hay nếu bạn muốn làm quen hoặc cải thiện kiến thức về môi trường PHP. Trước hết, bạn cần phải làm quen với việc quản lý phiên bản PHP.PHP Version Management Lifecycle
Phiên bản phụ PHP (PHP minor version) thường đi theo chu kỳ năm, mỗi phiên bản phụ sẽ được hỗ trợ trong 3 năm. Hai năm đầu là “hỗ trợ chủ động” sửa các lỗi thường gặp, và năm cuối là “hỗ trợ bảo mật”. Sau khi kết thúc chu kỳ 3 năm, phiên bản PHP đó sẽ không được hỗ trợ nữa.
Bạn có thể tìm những phiên bản PHP hiện đang được hỗ trợ tại đây.Tại thời điểm viết bài PHP 5.5 được hỗ trợ bảo mật, PHP 5.6 và 5.7 đang được “hỗ trợ chủ động”.
Sửa thử một lỗi
Trước khi biểu diễn một workflow căn bản, hãy giải quết bug #71635 trên bugs.php.net. Bug report có chỉ ra segfault khi gọi
- Code:
DatePeriod::getEndDate()
khi không có date. Vì vậy, việc đầu tiên ta cần làm là xác nhận tính hợp lệ.[/size]
Với các lỗi nhỏ (ít hoặc không yêu cầu thiết lập môi trường), đầu tiên ta sẽ xem thử có thể dùng 3v4l tái tạo lại bug được không (3v4l là một công cụ cho phép ta chạy những đoạn code nhỏ trên hàng trăm phiên bản PHP khác nhau). Việc này sẽ cho phép ta xác đinh nhanh chóng liệu các phiên bản PHP cũ hơn (nhưng vẫn được hỗ trợ) có bị ảnh hưởng hay không. Như ta thấy, PHP cho ra segfault cho tất cả phiên bản từ 5.6.5 đến 7.0.4.
Ta sẽ luôn phải tái tạo bug cục bộ trước khi fix (dù có dùng được 3v4l hay không). Bạn sẽ phải fork php/php-src và clone fork cục bộ. Nếu bạn đã thực hiện bước này từ trước, hay update clone, và truy lại tất cả các release được tag gần nhất (có
- Code:
git remote update
).[/size]
Ta sẽ làm việc với nhánh PHP 5.6 trước vì đó là phiên bản thấp nhất bị ảnh hưởng (đồng thời vẫn được “hỗ trợ chủ động”). (Nếu bug này ảnh hưởng đến PHP 5.5, ta sẽ vẫn không dùng phiên bản này và làm việc với PHP 5.6 vì bug này không liên quan đến bảo mật). Workflow chuẩn khi kiểm tra fix lỗi là tập trung fix vào phiên bản thấp nhất (nhưng vẫn còn được hỗ trợ) bị ảnh hưởng. Một developer của php/php-src sẽ gộp fix này nếu cần thiết.
Vậy thì, hãy checkout một copy của nhánh PHP 5.6:
1 2 3 | git checkout -b fix-dateperiod-segfault upstream/php-5.6 |
Kế đến, chúng ta sẽ build PHP và cố gắng tái tạo cụ bộ segfault bằng cách tạo một file (như segfault.php) code sau:
1 2 3 4 5 6 | $period = new DatePeriod(new DateTimeImmutable("now"), new DateInterval("P2Y4DT6H8M"), 2); var_dump($period->getEndDate()); |
Tiếp đó, ta sẽ chạy segfault.php PHP binary vừa build:
1 2 3 | sapi/cli/php -n segfault.php |
(cờ
- Code:
-n
có nghĩa rằng file php.ini sẽ không được dùng cho cấu hình, từ đó chặn load of errors mỗi khi bạn thực thi một file với PHP binary cục bộ. Điều này sẽ rất tiện nếu bạn load các extension (phần mở rộng) tùy chỉnh vào file .ini mặc định.)[/size]
Một khi đã xác định có thể kích hoạt cục bộ, ta có thể tạo một test. Hãy gọi file test này là bug71635.phpt và đặt nó vào thư mục ext/date/tests/ với các nội dung sau:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | --TEST-- Bug #71635 (segfault in DatePeriod::getEndDate() when no end date has been set) --FILE-- date_default_timezone_set('UTC'); $period = new DatePeriod(new DateTimeImmutable("now"), new DateInterval("P2Y4DT6H8M"), 2); var_dump($period->getEndDate()); ?> --EXPECT-- NULL Sau khi chạy test trên, ta thấy sẽ không qua: make test TESTS=ext/date/tests/bug71635.phpt |
Chúng ta giờ đây sẽ chạy một debugger (tự chọn) lên file segfault.php đã tạo trước đó. (Tôi dùng LLDB tích hợp chung với Mac OS X, nhưng GDB là một debugger tương tự có hỗ trợ lệnh overlap.)
1 2 3 | lldb sapi/cli/php a.php |
(Lần này, lệnh
- Code:
-n
không được dùng đến để tránh xung đột với lldb.)[/size]
Sau khi vào LLDB debugger, ta gõ
- Code:
run
để thực thi file. Bạn có thể thấy rõ segfault xảy ra ở đâu trong đoạn code dưới đây:[/size]
Tuy frame đầu không cho thấy quá nhiều thông tin (trừ khi bạn lập trình trên asm), bạn vẫn có thể thấy chưng trình ngừng vì
- Code:
EXC_BAD_ACCESS
. Ta cũng có thể thấy pointer address dự định được sử dụng là
[/size]
- Code:
0x0
(null).[/size]
Dùng lên
- Code:
bt
cho ta thấy backtrace của segfault (mỗi frame dẫn đến segfault). Nhìn vào frame #1 (bằng cách nhập
[/size]
- Code:
frame select 1
), ta đã quay lại C code và có thể thấy được dòng code gây ra vấn đề:[/size]
Từ đây, ta có thể thấy thử phạm là biến
- Code:
dpobj->end
bị null, từ đó cố tham chiếu ngược nó, gây segfault. Vì vậy, ta sẽ đặt một check phía trên để xem liệu
[/size]
- Code:
dpobj->end
có phải là null pointer hay không, nếu đúng, ta chỉ việc quay lại từ hàm này (càng sớm càng tốt):[/size]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | 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; } } |
Hoàn toàn quay lại từ một method sẽ khiến cho hàm trả kết quả
- Code:
null
(giống như kết quả thất bại của mọi hàm internal PHP khác). Điều này sảy ra vì biến
[/size]
- Code:
return_value
(truy cập được trong mọi hàm definition) giữ giá trị thật sự được trả về (được mặc định thành null).[/size]
Vậy hãy build PHP và chạy lại test:
1 2 3 | make test TESTS=ext/date/tests/bug71635.phpt |
Bạn giờ sẽ có thể qua test. Giờ đây ta đã có thể ủy thác file được update và test lỗi tương ứng, và rồi đăng PR với nhánh php/php-src 5.6.
Kết
bài viết này đã mô tả một workflow đơn giản được dùng khi gỡ lỗi trong core. Gỡ lỗi yêu cầu rất ít kiến thức C và là một bước khởi điểm tuyệt vời trước khi tìm hiểu chuyên sâu hơn về.
Sửa lỗi cũng là một thách thức mới lạ với các bạn đã quá quen thuộc với các thách thức trong thuật toán (bạn có thể tìm hiểu thêm tại Project Euler). Và với kho bug lên đến con số 5000, có khi bạn xem hoài cũng không hết!
Đăng ký thành viên và bình luận
Bạn cần phải đăng ký để bình luận.
Tạo tài khoản
Tham gia vào cộng đồng bằng cách tạo tại khoản, nó thật dễ dàng!
Tạo tài khoản mới
Trang 1 trong tổng số 1 trang
Permissions in this forum:
Bạn không có quyền trả lời bài viết
Wed Feb 21, 2024 11:49 am by NIK SIURI
» [PhpBB3] BeastVN
Sun Feb 11, 2024 3:07 pm by hoanglongnhatbao
» [PhpBB2] IPS Community
Sun Feb 11, 2024 3:06 pm by hoanglongnhatbao
» [PunBB] HEEDragon
Sun Feb 11, 2024 3:04 pm by hoanglongnhatbao
» [PunBB] Facebook
Sun Feb 11, 2024 3:04 pm by hoanglongnhatbao
» [PunBB] Back (Mới)
Sun Feb 11, 2024 3:03 pm by hoanglongnhatbao
» [PhpBB3] CODE GAME
Sun Feb 11, 2024 2:37 pm by hoanglongnhatbao
» [Invision] VNXF
Sun Feb 11, 2024 2:36 pm by hoanglongnhatbao
» [Simple Theme] Silver Plain V4.1
Sun Feb 11, 2024 2:19 pm by hoanglongnhatbao