Làm thế nào để thực hiện gỡ lỗi thủ công? [đóng cửa]


8

Giả sử bạn không có sẵn trình gỡ lỗi, cách tiếp cận hiệu quả đối với mã gỡ lỗi không hoạt động (như mong đợi) là gì?


20
"Công cụ gỡ lỗi hiệu quả nhất vẫn là suy nghĩ cẩn thận, cùng với các tuyên bố in được đặt một cách thận trọng." - Brian Kernighan

3
Hoàn toàn đồng ý. Công cụ sửa lỗi mạnh mẽ nhất vẫn là in báo cáo. Một lời khuyên khác là gỡ lỗi mã thực tế chứ không phải các bình luận.
romeroqj

4
@jromero: tôi sẽ không nói các bản in là "mạnh nhất". Phổ biến nhất và dễ sử dụng, chắc chắn.
whatsisname

1
Câu nói đó của Kernighan khiến tôi ước mình có thể hạ thấp ý kiến. In gỡ lỗi tuyên bố là một công cụ của phương sách cuối cùng.
Mason Wheeler

2
@Mason: Câu hỏi giả định rằng trình gỡ lỗi không có sẵn (vì vậy cách "thực sự" để theo dõi thực thi đã biến mất), vậy bạn sẽ sử dụng cách nào khác để theo dõi thực thi?

Câu trả lời:


7

Có một số kỹ thuật:

  1. Ghi nhật ký. Nếu bạn không có quyền truy cập tệp, hãy đăng nhập vào bảng điều khiển nối tiếp hoặc bất kỳ thiết bị đầu ra nào khả dụng. Đó là một ý tưởng tốt để luôn luôn viết mã của bạn khi đăng nhập, cho phép biên dịch có điều kiện cho các cấp ghi nhật ký khác nhau, từ 'không' đến 'quá mức'.

  2. Cắt nó xuống. Loại trừ các phần của mã của bạn xung quanh một lỗi đáng ngờ từng điểm một và phân tích những gì bạn đã làm khi lỗi biến mất.

  3. Khẳng định hoặc hợp đồng. Đó là một ý tưởng tốt để nhồi mã của bạn với các xác nhận ngay từ đầu. Chúng không chỉ giúp gỡ lỗi mà còn đóng vai trò là tài liệu bổ sung cho mã của bạn.

  4. Tương tự như 2. - thay đổi đầu vào của bạn và cải tổ lại mã trừ khi lỗi biến mất hoặc thay đổi hành vi của nó. Thường là một ý tưởng tốt để chơi với các mức tối ưu hóa khác nhau (nếu bạn đang mã hóa bằng C hoặc C ++), vì các lỗi liên quan đến con trỏ có xu hướng cực kỳ dễ bay hơi trong hành vi của chúng.

  5. Phiên bản tự động của 3. - sử dụng mã cụ, ví dụ: chạy nhị phân theo valgrind.

Và tất nhiên còn nhiều công cụ và thủ thuật khác, tùy thuộc vào bản chất của môi trường thực thi và mã của bạn.


1
-1: Không thể đồng ý 4). Bạn dường như đang đề xuất nó như là một giải pháp cho lỗi? Nếu vậy đó là xấu xa và bạn có một vấn đề. Tất cả những gì nó làm là làm cho các triệu chứng biến mất - nó vẫn ở đó, bạn đã ẩn nó .... bây giờ ....
mattnz

@mattnz, tâm giải thích? Tôi đề xuất phương pháp này như là một giải pháp thay thế cho trình gỡ lỗi tương tác. Mà, lần lượt, chỉ nổi bật các triệu chứng, không phải là nguyên nhân thực tế. 4) là một cách để xác định một vấn đề, không phải là một giải pháp. Trong thực tế, cách tiếp cận của tôi tốt hơn nhiều so với gỡ lỗi trong hầu hết các trường hợp, vì nó mang lại độ bao phủ tốt hơn. Vì vậy, có khả năng bạn không hiểu những gì tôi đề xuất. Hãy thử đọc lại.
SK-logic

Tôi đã thấy các nhà phát triển sử dụng các hành động được nêu trong Bước 4 để "sửa chữa" một lỗi bằng cách sử dụng "Tôi có thể làm cho nó xảy ra, bây giờ tôi không thể, tôi đã sửa nó - gửi nó". Bài viết của bạn cho thấy phương pháp này cung cấp sửa lỗi hợp lệ.
mattnz

@mattnz, không, nó không đề xuất bất cứ điều gì như thế này. Tôi đang mô tả một cách để điều tra một lỗi, không phải sửa nó. Trình gỡ lỗi không sửa lỗi và câu hỏi là về một giải pháp thay thế cho trình gỡ lỗi.
SK-logic

18

Nhận một đồng nghiệp và giải thích vấn đề một cách chi tiết trong khi bạn đi qua các mã rắc rối từng bước.

Thường xuyên hành động giải thích làm rõ cho đồng nghiệp hoặc chính bạn.


12
+1 Và nếu bạn không tìm thấy đồng nghiệp, hãy sử dụng gấu bông .
Péter Török

4
@ Péter Török: Tôi không biết ... gấu bông chỉ có xu hướng nhìn lại bằng đôi mắt nút lạnh lẽo của chúng ... phớt lờ mọi điều bạn nói, khiến bạn cảm thấy vô dụng, nhỏ bé, không đáng kể ... Nó làm cho việc gỡ rối với một con gấu bông .. . khó khăn.
Thất vọngWithFormsDesigner

1
@FrustratedWithFormsDesigner, vui lòng xem liên kết tôi đã thêm.
Péter Török

2
@Peter, tôi sợ rằng việc có một kệ đầy gấu bông sẵn sàng để đồng nghiệp lấy để gỡ lỗi, có thể gây ấn tượng sai cho khách hàng.

1
@FrustratedWithFormsDesigner: Và nó khác với nhiều đồng nghiệp như thế nào
mattnz

3

Có một hệ thống đăng nhập để quản lý đầu ra chương trình? Có ít nhất một giao diện điều khiển để in hoặc tập tin bạn có thể ghi vào? Sử dụng bảng điều khiển hoặc tệp nhật ký là cách bạn có thể gỡ lỗi mà không cần trình gỡ lỗi. Cung cấp cho chương trình một đầu vào sao cho bạn biết đầu ra sẽ là gì, sau đó xác minh rằng đầu ra hoạt động và đảm bảo việc ghi nhật ký của bạn cung cấp cho bạn nhiều chi tiết của quy trình. Sau đó thử với một đầu vào cung cấp đầu ra sai. hy vọng, các bản ghi sẽ cung cấp cho bạn một dấu vết chi tiết về những gì đã sai.


Bạn có thể sử dụng bất cứ thứ gì NHƯNG một trình gỡ lỗi của loại gdb hoặc những gì bạn sẽ tìm thấy trong IDE của mình
Anto

@Anto: Nghe có vẻ giống như một dòng từ bài tập về nhà, nhưng trong trường hợp đó, việc đăng nhập vào tệp hoặc bảng điều khiển không sử dụng trình gỡ lỗi như "gdb hoặc những gì bạn tìm thấy trong IDE của mình". gdb và các trình gỡ lỗi khác cho phép bạn đi qua từng dòng mã của mình và kiểm tra các giá trị của các biến khi chương trình chạy . Gỡ lỗi theo nhật ký có nghĩa là bạn phải sử dụng dấu vết (trong tệp hoặc bảng điều khiển) của quá trình thực thi chương trình sau khi kết thúc và tìm hiểu điều gì đã xảy ra.
Thất vọngWithFormsDesigner

Tôi biết, do đó, những gì bạn đề nghị được cho phép. Không, đây không phải là bất kỳ bài tập về nhà; Tôi đang học trung học và chúng tôi không có lập trình / cs nào cả.
Anto

2
@Anto: Ok. Nhược điểm duy nhất của phương pháp này là nếu bạn đang cố gắng gỡ lỗi một chương trình có vấn đề về đồng bộ hóa. Ví dụ: nếu đó là sự cố IPC thì các câu lệnh in / nhật ký của bạn có thể ảnh hưởng đến việc các tiến trình nói với nhau nhanh như thế nào và việc bật hoặc tắt đăng nhập có thể ảnh hưởng đến việc sự cố được sao chép hay không (trong trường hợp này, bạn thực sự phải đi với @ Lời khuyên của Thorbjørn Ravn Andersen). Trong một số trường hợp, ghi nhật ký có thể làm giảm hiệu suất nghiêm trọng, nhưng thường chỉ khi nhiều lần đăng nhập trong một hệ thống lớn khi xử lý một lượng dữ liệu rất lớn ... nhưng cần phải biết điều gì đó.
Thất vọngWithFormsDesigner

3

Phụ thuộc. Nó đã làm việc trước đây? Nếu mã được sử dụng để làm việc đột ngột, thì bạn nên kiểm tra rất kỹ những thay đổi gần đây nhất.


2
Cách tiếp cận này không nên được nhấn mạnh: lịch sử sửa đổi là một cách tuyệt vời để xác định các lỗi trong mã đã hoạt động trước đây - ngay cả khi thêm các tính năng mới.
edA-qa mort-ora-y

2
Tôi đã nghe nói rằng 'git bisect' tự động hóa nhiệm vụ này phần nào. Tôi vẫn chưa thử nó mặc dù.
Clayton Stanley

2

1) Làm bất cứ điều gì bạn cần làm để làm cho lỗi có thể tái tạo 100% hoặc gần 100% nhất có thể

2) Theo dõi sự cố, sử dụng printf () hoặc phương tiện ghi nhật ký khác. Đây là một nghệ thuật, mặc dù, và nó phụ thuộc vào bản chất của lỗi.

Nếu bạn hoàn toàn không biết gì về vị trí của lỗi, nhưng ví dụ bạn biết một điều kiện trở thành sai tại một thời điểm nào đó (trạng thái của chương trình bị hỏng - hãy gọi nó làBroken ()), bạn có thể tìm kiếm chi tiết / tìm kiếm phân vùng để tìm ra vị trí của vấn đề. Ví dụ: ghi lại giá trị của isBroken () ở đầu ở cuối các phương thức chính:

void doSomething (void)
{
    printf("START doSomething() : %d\n", isBroken());
    doFoo();
    doBar();
    printf("END doSomething() : %d\n", isBroken());
}

Nếu trong nhật ký bạn thấy

START doSomething() : 0
END doSomething() : 1

bạn biết có gì đó không ổn ở đó Vì vậy, bạn xóa tất cả các mã đăng nhập khác và thử phiên bản mới này:

void doSomething (void)
{
    printf("START doSomething() : %d\n", isBroken());
    doFoo();
            printf("AFTER doFoo() : %d\n", isBroken());
    doBar();
    printf("END doSomething() : %d\n", isBroken());
}

Bây giờ trong nhật ký bạn có thể thấy điều này

START doSomething() : 0
AFTER doFoo() : 0
END doSomething() : 1

Vì vậy, bây giờ bạn biết doBar () kích hoạt lỗi và bạn có thể lặp lại quy trình trên trong doBar (). Lý tưởng nhất là bạn sẽ thu hẹp lỗi thành một dòng duy nhất.

Tất nhiên điều này có thể giúp bạn tiết lộ các triệu chứng của lỗi chứ không phải nguyên nhân gốc - ví dụ: bạn tìm thấy một con trỏ NULL không nên là NULL, nhưng tại sao? Sau đó, bạn có thể đăng nhập lại, nhưng kiểm tra một điều kiện "bị hỏng" khác.

Nếu bạn gặp sự cố thay vì trạng thái bị hỏng, thì ít nhiều giống nhau - dòng cuối cùng của nhật ký cung cấp cho bạn một gợi ý về nơi mọi thứ bị phá vỡ.


2

Sau khi các câu trả lời khác không thành công , luôn có gỡ lỗi tìm kiếm nhị phân :

  1. Loại bỏ một phần nhất định (tốt nhất là một nửa) các nguyên nhân có thể (dòng mã, sửa đổi , đầu vào, v.v.)
  2. Cố gắng tái tạo vấn đề một lần nữa.
  3. Nếu vấn đề vẫn còn: quay lại bước 1.
  4. Nếu bạn chỉ còn một nguyên nhân (dòng mã, sửa đổi, phần đầu vào, v.v.): Hurrah! Thủ tục xuất cảnh.
  5. Nếu không: Bước 1 Hoàn nguyên, và bây giờ loại bỏ sự khác nửa.
  6. Quay trở lại bước 2.

Lưu ý: rõ ràng, kỹ thuật này chỉ hoạt động nếu bạn có thể tái tạo vấn đề một cách đáng tin cậy.


1. Loại bỏ một nửa nguyên nhân có thể. Vấn đề tan biến. 2. Khôi phục một nửa và loại bỏ nửa kia. Vấn đề tan biến. 3. Loại bỏ chỉ một vài nguyên nhân có thể. Vấn đề sẽ biến mất nếu bạn loại bỏ 20% tùy ý. 4. Bắt đầu kiểm tra hiệu suất, công cụ cơ bản và chạy trong vòng tròn. 5. Hoảng loạn.
SF.

Với những chữ cái lớn, thân thiện.
Jeroen

0

'"Công cụ gỡ lỗi hiệu quả nhất vẫn là suy nghĩ cẩn thận, cùng với các câu lệnh in được đặt một cách thận trọng." - Brian Kernighan 'Trong ngày đó có thể là sự thật! Phương pháp hiệu quả nhất là xem xét các bài kiểm tra đơn vị nhưng tôi đoán là bạn không có bài kiểm tra nào.


Tôi không có bất kỳ bài kiểm tra đơn vị nào vì tôi không có dự án hoặc mã cụ thể nào; Tôi chỉ yêu cầu phương pháp sửa lỗi
Anto

Tại sao trên trái đất, bạn sẽ bỏ phiếu cho câu trả lời này? Hãy ngừng tức giận trong bóng tối và bài kiểm tra đơn vị sau đó.

Không phải tôi là người bị hạ bệ nên đã khóc cho người khác
Anto

2
Kiểm thử đơn vị không thay thế gỡ lỗi, nó chỉ đơn giản là giúp ngăn chặn và hạn chế các lỗi. Điều này làm cho việc gỡ lỗi đơn giản hơn, khi một lỗi xảy ra trong một bài kiểm tra đơn vị được mã hóa. IME, hầu hết các lỗi khó khăn là trong các tương tác thành phần (khó kiểm tra đơn vị) và được phát hiện thường xuyên hơn trong các bộ kiểm tra cơ sở theo kiểu hồi quy.
Clayton Stanley

-1) Làm thế nào để bạn sửa mã được xác định bởi một thử nghiệm đơn vị bị hỏng - bạn gỡ lỗi nó ...... Các thử nghiệm đơn vị phát hiện lỗi, gỡ lỗi và gỡ lỗi được sử dụng để sửa lỗi.
mattnz

0

Nó phụ thuộc vào lỗi.

Nếu lỗi là loại 'tại sao mã lại làm A', thì có thể hữu ích để kiểm tra sự hiểu biết của bạn về mã xung quanh vị trí của 'mã làm A'. Giới thiệu mã mới mà bạn dự kiến ​​sẽ tạo ra các lỗi mới (mã này sẽ làm cho nó làm B, điều này sẽ làm cho nó làm C). Tôi thường nhanh chóng tìm thấy một số mã mới tạo ra hành vi mà tôi không mong đợi. Sau đó, tôi kiên nhẫn chờ đợi trong khi tâm trí của tôi xây dựng một mô hình tinh thần cập nhật về hành vi mã để thay đổi cuối cùng có ý nghĩa, và sau đó thay đổi mô hình tinh thần đó thường giải thích lý do tại sao mã đang thực hiện A.

Trường hợp thứ hai đã được thảo luận chi tiết ở đây. Trường hợp bạn đã thừa hưởng mã, không có mô hình tinh thần vững chắc về cách mã hoạt động, không có ý tưởng hay về vị trí cụ thể của lỗi, v.v. Trong trường hợp này, hãy truy sâu / phân chia và- phương pháp chinh phục với báo cáo in có thể làm việc. Và nếu nó nằm dưới sự kiểm soát nguồn, hãy đảm bảo kiểm tra thay đổi mã gần đây nhất.


0

Mở rộng trên "Công cụ gỡ lỗi hiệu quả nhất vẫn là suy nghĩ cẩn thận, cùng với các tuyên bố in được đặt một cách thận trọng."

Đầu tiên, cố gắng thu hẹp thời điểm lỗi xảy ra. Làm cho các triệu chứng người dùng có thể quan sát hệ thống quan sát được. (giả sử, một số chuỗi thay đổi thành vô nghĩa, thêm một vòng lặp thăm dò nội dung của tập lệnh và kích hoạt gỡ lỗi của bạn khi nó thay đổi.) Tất nhiên nếu lỗi là sự cố, hãy thêm xử lý segfault.

Sau đó cố gắng thu hẹp luồng nếu sự cố xảy ra với môi trường đa luồng. Cung cấp cho mỗi luồng một mã định danh và kết xuất nó khi lỗi xảy ra.

Một khi bạn có chủ đề, hãy rắc mã của chủ đề đã cho bằng các bản in một cách cẩn thận để đóng đinh xuống điểm mà nó xuất hiện.

Sau đó quay lại nơi xảy ra hành động thực tế xảy ra (hành động phá hoại thường sẽ khá nhiều trước khi dữ liệu bị hỏng gây ra sự cố.) Kiểm tra cấu trúc / biến nào xảy ra gần đó trong bộ nhớ, quan sát các vòng lặp ảnh hưởng đến chúng, kiểm tra các điểm trong đó giá trị bị hỏng được ghi vào.

Một khi bạn có điểm gây ra sự cố, trước khi sửa nó, hãy suy nghĩ kỹ xem hành vi đúng phải là gì.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.