Thông báo

QUAN TRỌNG

Tuyên bố từ chối trách nhiệm !!!
Chúng tôi không chịu trách nhiệm về bài đăng của các thành viên, nếu bạn có vấn đề gì vui lòng liên hệ với các quan chức địa phương nơi bạn ở, chúng tôi sẽ không giải quyết bất cứ vấn đề gì khi bạn sử dụng forum.

Vì một cộng đồng Forumvi phát triển !
December 2018
MonTueWedThuFriSatSun
     12
3456789
10111213141516
17181920212223
24252627282930
31      

Calendar Calendar

Poll
Ads

    No ads available.


    PHP: Fix bug PHP Core

    Xem chủ đề cũ hơn Xem chủ đề mới hơn Go down

    avatar
    DenDenMuShi
    Thành viên mới
    Thà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
    Xem lý lịch thành viên

    Bài gửiDenDenMuShi on Sun Mar 11, 2018 12:06 am


    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()
    [size]
     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]
    ).[/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
    [size]
     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
    [size]
     không được dùng đến để tránh xung đột với lldb.)[/size]

    Sau khi vào LLDB debugger, ta gõ 
    Code:
    run
    [size]
     để 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
    [size]
    . Ta cũng có thể thấy pointer address dự định được sử dụng là 
    [/size]
    Code:
    0x0
    [size]
     (null).[/size]

    Dùng lên 
    Code:
    bt
    [size]
     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
    [size]
    ), 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
    [size]
     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
    [size]
     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
    [size]
     (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
    [size]
     (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!

    Xem chủ đề cũ hơn Xem chủ đề mới hơn Về Đầu Trang

    Đă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

    Đăng nhập

    Đã có tài khoản? Không thành vấn đề, hãy đăng nhập.


    Đăng nhập

     
    Permissions in this forum:
    Bạn không có quyền trả lời bài viết