Câu hỏi Theo dõi truy cập biến trong C / C ++


Tôi đang làm việc trên một tiêu chí bảo hiểm cho mã đa luồng và là một phần của nó muốn ghi lại truy cập vào các biến. Ví dụ, trong đoạn code dưới đây tôi muốn ghi lại biến đó x đã được viết và y, z, a[i], và tôi đã được đọc từ.

x = y * (int)z + a[i]

Tôi đã xem xét việc này bằng cách sử dụng RecursiveASTVisitor của Clang và sửa đổi nguồn để bao gồm chức năng ghi âm. Tuy nhiên, tôi không chắc liệu đây có phải là một cách tiếp cận hợp lý hay không vì sự hiểu biết của tôi về cách Clang hoạt động rất không đầy đủ.

Hiện tại, khi tôi tìm thấy một câu lệnh, tôi kiểm tra xem đó có phải là BinaryOperator, UnaryOperator, Cast, or DeclRefExpr. (Tôi sẽ mở rộng những gì nó có khả năng một khi tôi có những điều cơ bản làm việc.) Nếu đó là một BinaryOperator, UnaryOperator, or Cast Tôi kiểm tra biểu thức của subexpressions. Nếu đó là một DeclRefExpr tôi có thể kiểm tra xem biểu thức là một lvalue hoặc rvalue (một lần nữa, đơn giản hóa cho bây giờ), nhưng một khi tôi đã tìm thấy DeclRefExpr họ luôn luôn lvalues. Để xác định xem chúng có được sử dụng như lvalues or rvalues Tôi phải kiểm tra cha mẹ của nó, nếu nó là một lvaluetorvalue cast nó đã được sử dụng như một rvalue.

Tôi rất cảm thấy như tôi đang dùng cách tiếp cận sai với vấn đề này vì tôi chỉ có thể thấy nó phức tạp hơn nhiều khi tôi phải xem xét mã phức tạp hơn.

Liệu có cách nào tốt hơn để tiếp cận điều này?

Cảm ơn bạn

Chỉnh sửa

Tôi không có ý định ghi lại thông tin này một cách tĩnh lặng. Tôi dự định sẽ tìm cách sử dụng các biến và chèn mã sẽ ghi lại quyền truy cập vào các biến này khi mã được chạy.

Ví dụ: được cung cấp mã ở trên (x = y * (int)z + a[i];), Tôi muốn sản xuất một cái gì đó như

x = y * (int)z + a[i];
recordAccess(<file>, <line>, "x",    &x,    WRITE);
recordAccess(<file>, <line>, "y",    &y,    READ);
recordAccess(<file>, <line>, "z",    &z,    READ);
recordAccess(<file>, <line>, "a[i]", &a[i], READ);
recordAccess(<file>, <line>, "i",    &i,    READ);

8
2018-03-06 16:00


gốc


Bạn muốn sản xuất cái gì cho: * p = 0; ? Làm thế nào để bạn mong đợi để tìm ra tên biến được sửa đổi? - Ira Baxter
recordAccess (<file>, <line>, "* p", p, VIẾT) Tôi giả sử. - tgt
Điều đó không làm những gì bạn yêu cầu bạn muốn làm. Đầu tiên, nó là một truy cập vào biến p. Thứ hai, nó không liệt kê biến (hoặc khối heap được phân bổ) mà p điểm. Làm thế nào bạn sẽ nhận được bảo hiểm của các biến là chính xác? Con trỏ khá phổ biến ở cả C và C ++. - Ira Baxter
Tôi không hoàn toàn chắc chắn những gì bạn có ý nghĩa. Tôi muốn ghi lại rằng p đang được đọc và rằng * p đang được viết và từ các truy cập khác đến địa chỉ được trỏ tới bởi p Tôi biết các biến khác truy cập vào bộ nhớ đó. Bạn sẽ cung cấp một ví dụ về những gì bạn mô tả xin vui lòng? - tgt


Các câu trả lời:


Như những người khác đã chỉ ra, răng cưa làm cho điều này là không thể. Phân tích tĩnh của mã để trả lời các câu hỏi mà bạn quan tâm là không thể. Nếu nó bằng cách nào đó có thể lấy một tệp mã nguồn và xác định đầu ra chỉ bằng cách phân tích cú pháp, trình biên dịch sẽ tạo ra đầu ra của chương trình kết quả, thay vì một chương trình được biên dịch. Tóm lại, bạn đang cố gắng trả lời tạm dừng vấn đề.

Phân tích động là những gì bạn thực sự cần để trả lời các câu hỏi mà bạn có nhiều khả năng quan tâm nhất. Có một thị trường lớn trong phân tích động của phần mềm đa luồng.


1
2018-03-09 03:29



Việc thực hiện một phân tích động cho điều này là khó (không phải là không thể, nhưng cũng khó). Về bản chất, bạn phải thay thế mọi truy cập con trỏ trong mọi đơn vị biên dịch bằng cơ chế thu thập truy cập dữ liệu, có thể nắm bắt bằng cách nào đó vị trí mã nguồn của thực thể được tham chiếu. (Chúng tôi làm điều này với công cụ CheckPointer của chúng tôi [than ôi, giới hạn hiện tại đến C). - Ira Baxter
Tôi đồng ý! Những gì tôi đang cố gắng chỉ ra cho OP, là trong khi anh ta hoặc cô ta đã phát triển một trạng thái vấn đề hợp lý và được suy nghĩ tốt về giải pháp thì không đơn giản như vậy. Hoàn toàn hợp lý khi muốn phân tích truy cập đa luồng tới các vùng bộ nhớ. Tuy nhiên, nó không đơn giản như nó âm thanh. Lần cuối cùng tôi nhìn, Portland Group đã phát triển sản phẩm cho loại điều này. Tôi chưa bao giờ có niềm vui khi làm việc với họ. - Eric Urban


Vấn đề chính ở đây là bạn không xem xét răng cưa. Bạn sẽ chỉ có thể ghi lại các truy cập đơn giản, trực tiếp.

Nhưng trong trường hợp đó, một biểu hiện đơn giản AST khách truy cập là con đường chính để đi. Nhưng RecursiveASTVisitor của Clang nên, từ bộ nhớ, có thể cắt crap cho bạn và cho phép bạn truy cập trực tiếp vào các nút biến cuối cùng. Sau khi tất cả, nó nên ghé thăm tất cả các nút AST.


0
2018-03-06 16:08



Nhận xét đầu tiên của bạn chắc chắn là một vấn đề mà tôi cần phải giải quyết, nhưng tôi bắt đầu với một cái gì đó cơ bản hơn. Trong khi tất cả các nút AST được truy cập, tôi vẫn không chắc chắn về cách xác định nó đang được sử dụng như thế nào. Ví dụ, có đủ để chỉ đơn giản là kiểm tra xem nút cha của nó là một giá trị lvalue-to-rvalue đúc? - tgt
@tgt: Tôi không nghĩ vậy. Hãy xem xét một hàm gọi foo (x), với x được định nghĩa như một đối số tham chiếu. Là x đọc, hoặc viết? Bạn không thể nói mà không kiểm tra cơ thể của foo (và thậm chí điều đó có thể không đủ vì foo có thể (turing-complexly) gọi một cái gì đó khác.Để thêm vào các biến chứng của bạn, định nghĩa của cơ thể của foo có thể không được trong cùng một đơn vị biên dịch, bạn sẽ kiểm tra nó như thế nào? - Ira Baxter