Mở rộng Trình kiểm tra bộ nhớ để gỡ lỗi C/C++

Trong Chrome 92, chúng tôi đã ra mắt Trình kiểm tra bộ nhớ, một công cụ để kiểm tra vùng đệm bộ nhớ tuyến tính. Trong bài viết này, chúng ta sẽ thảo luận về cách chúng tôi cải thiện Trình kiểm tra cho việc gỡ lỗi C/C++ và những thách thức kỹ thuật gặp phải trong quá trình này.

Dưới đây là một số bài đăng trên blog có liên quan nếu bạn mới sử dụng tính năng gỡ lỗi C/C++ và Trình kiểm tra bộ nhớ:

Giới thiệu

Trình kiểm tra bộ nhớ cung cấp cho bạn các tuỳ chọn gỡ lỗi mạnh mẽ hơn cho vùng đệm bộ nhớ tuyến tính. Trong trường hợp C/C++, bạn có thể kiểm tra các đối tượng bộ nhớ C/C++ trong Bộ nhớ WebAssembly.

Việc nhận dạng byte của đối tượng trong số bộ nhớ WebAssembly xung quanh là một điểm bất tiện. Bạn phải biết kích thước của đối tượng và đếm số byte từ đầu đối tượng. Trong ảnh chụp màn hình bên dưới, byte đầu tiên của mảng int32 gồm 10 phần tử được chọn nhưng không rõ ngay những byte nào khác thuộc về mảng này. Sẽ thật tuyệt nếu bạn có thể nhận ra ngay tất cả các byte thuộc về đối tượng.

Ảnh chụp màn hình của trình kiểm tra bộ nhớ ban đầu với một byte được làm nổi bật

Làm nổi bật đối tượng trong Trình kiểm tra bộ nhớ

Kể từ Chrome 107, Trình kiểm tra bộ nhớ sẽ làm nổi bật tất cả các byte của đối tượng bộ nhớ C/C++. Điều này giúp bạn phân biệt các vùng nhớ này với bộ nhớ xung quanh.

Ảnh chụp màn hình của trình kiểm tra bộ nhớ đã cập nhật với một mảng được làm nổi bật rực rỡ

Hãy xem video dưới đây để thấy Trình kiểm tra bộ nhớ hoạt động. Khi bạn hiển thị mảng x trong Trình kiểm tra bộ nhớ, bộ nhớ được làm nổi bật sẽ xuất hiện trong Trình xem bộ nhớ cùng với một khối mới ngay phía trên. Khối này sẽ nhắc bạn tên và loại của bộ nhớ được đánh dấu. Nhấp vào khối để chuyển đến bộ nhớ của đối tượng. Nếu bạn di chuột qua khối, một biểu tượng dấu thập sẽ xuất hiện – hãy nhấp vào biểu tượng đó để xoá phần đánh dấu.

Khi bạn chọn một byte nằm ngoài đối tượng bạn kiểm tra, phần đánh dấu sẽ mất tiêu điểm để tránh làm bạn mất tập trung. Để lấy nét lại, hãy nhấp lại vào bất kỳ byte nào của đối tượng hoặc vào khối.

Tính năng hỗ trợ làm nổi bật đối tượng không chỉ giới hạn ở các mảng. Bạn cũng có thể kiểm tra cấu trúc, đối tượng và con trỏ. Những thay đổi này giúp bạn dễ dàng khám phá bộ nhớ của ứng dụng C/C++ hơn bao giờ hết!

Bạn có muốn dùng thử không? Bạn sẽ cần:

  • Có Chrome 107 trở lên.
  • Cài đặt Tiện ích DWARF C/C++.
  • Bật tính năng gỡ lỗi DWARF trong DevTools > Cài đặt. Settings (Cài đặt) > Experiments (Thử nghiệm) > WebAssemble Debugging: Enable DWARF support (Gỡ lỗi WebAssemble: Bật tính năng hỗ trợ DWARF).
  • Mở trang minh hoạ này.
  • Làm theo hướng dẫn trên trang.

Ví dụ về gỡ lỗi

Trong phần này, hãy xem một lỗi đồ chơi để minh hoạ cách bạn có thể sử dụng Trình kiểm tra bộ nhớ để gỡ lỗi C/C++. Trong mã mẫu bên dưới, lập trình viên tạo một mảng số nguyên và quyết định sử dụng phép tính con trỏ để chọn phần tử cuối cùng. Thật không may, lập trình viên đã mắc lỗi khi tính toán con trỏ và bây giờ thay vì in phần tử cuối cùng, chương trình in các giá trị vô nghĩa.

#include <iostream>

int main()
{
    int numbers[] = {1, 2, 3, 4};
    int *ptr = numbers;
    int arraySize = sizeof(numbers)/sizeof(int);
    int* lastNumber = ptr + arraySize;  // Can you notice the bug here?
    std::cout <<../ *lastNumber <<../ '\n';
    return 0;
}

Lập trình viên chuyển sang Trình kiểm tra bộ nhớ để gỡ lỗi vấn đề. Bạn có thể theo dõi bản minh hoạ này! Trước tiên, họ kiểm tra mảng trong Trình kiểm tra bộ nhớ và thấy rằng mảng numbers chỉ chứa các số nguyên 1, 2, 34 như dự kiến.

Ảnh chụp màn hình trình kiểm tra bộ nhớ đã mở với một mảng int32 đã kiểm tra. Tất cả phần tử mảng đều được làm nổi bật.

Tiếp theo, họ sẽ thấy biến lastNumber trong ngăn Scope (Phạm vi) và nhận thấy rằng con trỏ trỏ đến một số nguyên bên ngoài mảng! Với kiến thức này, lập trình viên nhận ra rằng họ đã tính sai độ dời con trỏ ở dòng 8. Đáng lẽ phải là ptr + arraySize - 1.

Ảnh chụp màn hình của trình kiểm tra bộ nhớ đã mở cho thấy bộ nhớ được đánh dấu được con trỏ có tên &quot;lastNumber&quot; trỏ đến. Bộ nhớ được đánh dấu nằm ngay sau byte cuối cùng của mảng được đánh dấu trước đó.

Mặc dù đây là ví dụ về đồ chơi, nhưng nó minh hoạ cách làm nổi bật đối tượng truyền tải hiệu quả kích thước và vị trí của đối tượng bộ nhớ, giúp bạn hiểu rõ hơn về những gì đang diễn ra bên trong bộ nhớ của ứng dụng C/C++.

Cách Công cụ cho nhà phát triển xác định nội dung cần làm nổi bật

Trong phần này, chúng ta sẽ xem xét hệ sinh thái công cụ hỗ trợ gỡ lỗi C/C++. Cụ thể, bạn sẽ tìm hiểu cách Công cụ cho nhà phát triển, V8, Tiện ích DWARF C/C++ và Emscripten có thể gỡ lỗi C/C++ trong Chrome.

Để khai thác tối đa tính năng gỡ lỗi C/C++ trong DevTools, bạn cần có hai điều:

  • Tiện ích C/C++ DWARF đã cài đặt trong Chrome
  • Các tệp nguồn C/C++ được biên dịch sang WebAssembly bằng trình biên dịch Emscripten mới nhất theo hướng dẫn trong bài đăng trên blog này

Nhưng tại sao? V8 , công cụ JavaScript và WebAssembly của Chrome, không biết cách thực thi C hoặc C++. Nhờ Emscripten, một trình biên dịch C/C++ sang WebAssembly, bạn có thể biên dịch các ứng dụng được tạo bằng C hoặc C++ dưới dạng WebAssembly và thực thi các ứng dụng đó trong trình duyệt!

Trong quá trình biên dịch, emscripten sẽ nhúng dữ liệu gỡ lỗi DWARF vào tệp nhị phân của bạn. Nói chung, dữ liệu này giúp tiện ích xác định những biến WebAssembly tương ứng với biến C/C++ của bạn, v.v. Bằng cách này, DevTools có thể hiển thị cho bạn các biến C++ mặc dù V8 thực sự đang chạy WebAssembly. Nếu bạn tò mò, hãy xem bài đăng trên blog này để biết ví dụ về dữ liệu gỡ lỗi DWARF.

Vậy điều gì thực sự sẽ xảy ra khi bạn tiết lộ lastNumber? Ngay khi bạn nhấp vào biểu tượng bộ nhớ, DevTools sẽ kiểm tra xem bạn muốn kiểm tra biến nào. Sau đó, trình bổ trợ này truy vấn tiện ích về loại dữ liệu và vị trí của lastNumber. Ngay sau khi tiện ích phản hồi thông tin đó, Trình kiểm tra bộ nhớ có thể cho thấy lát bộ nhớ liên quan và biết được loại bộ nhớ, đồng thời có thể cho bạn biết kích thước của đối tượng.

Nếu xem lastNumber trong ví dụ trước, bạn có thể nhận thấy chúng ta đã kiểm tra lastNumber: int *, nhưng chip trong Trình kiểm tra bộ nhớ cho biết *lastNumber: int, điều gì mang lại? Trình kiểm tra sử dụng tính năng tham chiếu con trỏ kiểu C++ để cho biết loại đối tượng hiển thị với bạn! Nếu bạn kiểm tra một con trỏ, công cụ kiểm tra sẽ cho bạn biết con trỏ trỏ đến vị trí nào.

Duy trì các điểm nổi bật trên các bước của trình gỡ lỗi

Khi bạn hiển thị một đối tượng trong Trình kiểm tra bộ nhớ và thực hiện bước với trình gỡ lỗi, Trình kiểm tra sẽ duy trì trạng thái làm nổi bật nếu cho rằng trạng thái đó vẫn có thể áp dụng. Ban đầu, chúng tôi không có tính năng này trong lộ trình phát triển, nhưng nhanh chóng nhận ra rằng điều này làm ảnh hưởng đến trải nghiệm gỡ lỗi của bạn. Hãy tưởng tượng bạn phải kiểm tra lại mảng sau mỗi bước như trong video bên dưới!

Khi trình gỡ lỗi gặp một điểm ngắt mới, Trình kiểm tra bộ nhớ sẽ truy vấn lại V8 và phần mở rộng cho biến liên kết với phần đánh dấu trước đó. Sau đó, hàm này so sánh vị trí và loại của các đối tượng. Nếu các từ đó khớp nhau, thì phần được làm nổi bật sẽ vẫn xuất hiện. Trong video ở trên, có một vòng lặp for ghi vào mảng x. Những thao tác này không làm thay đổi loại hoặc vị trí của mảng, nên mảng được đánh dấu.

Bạn có thể thắc mắc điều này ảnh hưởng như thế nào đến con trỏ. Nếu bạn có một con trỏ được làm nổi bật và chỉ định lại con trỏ đó cho một đối tượng khác, thì vị trí cũ và mới của các đối tượng được làm nổi bật sẽ khác nhau và phần làm nổi bật sẽ biến mất. Vì đối tượng mới được trỏ đến có thể nằm ở vị trí bất kỳ trong Bộ nhớ WebAssembly và có thể sẽ ít liên quan đến vị trí bộ nhớ trước đó, nên việc xoá phần đánh dấu sẽ rõ ràng hơn so với việc chuyển đến vị trí bộ nhớ mới. Bạn có thể làm nổi bật con trỏ một lần nữa bằng cách nhấp vào biểu tượng bộ nhớ của con trỏ trong ngăn Phạm vi.

Kết luận

Bài viết này mô tả những điểm cải tiến của chúng tôi đối với Trình kiểm tra bộ nhớ để gỡ lỗi C/C++. Chúng tôi hy vọng các tính năng mới sẽ đơn giản hoá việc gỡ lỗi bộ nhớ của ứng dụng C/C++! Nếu bạn có đề xuất để cải thiện thêm, hãy cho chúng tôi biết bằng cách gửi lỗi!

Bước tiếp theo

Để tìm hiểu thêm, hãy xem: