2013-06-05 23 views
12

Tôi có một chức năng cụ thể (trình xử lý tín hiệu) mà tôi muốn phát hiện đệ quy, để tìm hiểu xem hàm có trực tiếp hay gián tiếp được gọi. Bit khó hiểu là hàm gọi một số mã không thuộc quyền kiểm soát của nó tại một thời điểm, và mã đó có thể làm bất cứ điều gì.Phát hiện đệ quy mạnh mẽ ngay cả khi có các bước nhảy không phải cục bộ

Thông thường, tôi chỉ muốn viết một cái gì đó giống như

void foo() { 
    static int recursed = 0; 
    if(recursed) { 
     ... 
    } 
    recursed = 1; 
    othercode(); 
    recursed = 0; 
} 

nhưng trong trường hợp này, tôi đang lo ngại rằng othercode thể sử dụng một longjmp hoặc tương tự để thoát ra khỏi, dẫn đến recursed còn lại tại 1. Trong sự kiện mà chức năng của tôi bị nhảy ra theo cách này, tôi muốn đảm bảo rằng nó không tự coi là đệ quy nếu được gọi sau (thực tế là nó là longjmp 'd ra khỏi không phải là một vấn đề khác).

Lưu ý: Tôi xem xét khả năng là longjmp. othercode là trình xử lý tín hiệu chuỗi từ một số mã khác trong tự nhiên và có trình xử lý tồn tại cho ví dụ: SIGSEGV sử dụng longjmp để khôi phục ngữ cảnh (ví dụ như trình xử lý ngoại lệ "bảo vệ lỗi"). Lưu ý rằng việc sử dụng longjmp trong trình xử lý tín hiệu đồng bộ nói chung là an toàn. Trong bất kỳ trường hợp nào, tôi không đặc biệt quan tâm liệu mã khác có an toàn chút nào không, bởi vì nó không phải là điều tôi kiểm soát.

+0

Bạn đang lo lắng về 'longjmp' có khả năng xảy ra, hoặc chỉ là đó là khả năng? – Patashu

+0

@Patashu: Có khả năng. Xem chỉnh sửa của tôi. – nneonneo

+0

Tiêu đề câu hỏi cần được chỉnh sửa để cụ thể hơn, giống như 'Phát hiện lại quyền truy cập ngay cả khi longjmp được sử dụng' – Patashu

Trả lời

3

Không chắc chính xác mã sẽ trông như thế nào, nhưng thay vì một int tĩnh, bạn có thể có một khoảng trống tĩnh *. Thay vì đặt nó thành 1, đặt nó để trỏ đến khung ngăn xếp hiện tại. Ngoài việc kiểm tra xem nó có phải là nonzero hay không, bạn hãy kiểm tra để đảm bảo rằng địa chỉ trả về từ khung ngăn xếp tiếp theo sau recursed trên thực tế trỏ đến một vị trí trong mã của foo và cũng có thể là recursed ở trên con trỏ ngăn xếp hiện tại, tức là không xuất hiện.

Nghe có vẻ rất dễ vỡ và phụ thuộc vào kiến ​​trúc.

+0

Hoặc có thể đơn giản hơn khi nhìn vào địa chỉ trả về từ các điểm khung xếp của foo ngay sau khi lệnh gọi đến foo, nhưng điều đó sẽ * chắc chắn * là không di động. – morningstar

+0

Tôi đã xem xét điều này. Nó hoạt động thực sự tốt, ngoại trừ một trường hợp góc nhỏ: giả sử 'othercode' nhảy tới một hàm ở trên' foo', hàm này gọi một số hàm khác phân bổ (nhưng không hoàn toàn sử dụng) một vùng đệm khổng lồ, sau đó kết thúc kích hoạt 'foo'. Nếu tôi không may mắn, bộ đệm ngăn xếp khổng lồ đều di chuyển con trỏ ngăn xếp bên dưới 'foo' và giữ nguyên ngăn xếp' foo' ban đầu, làm cho nó trông giống như đệ quy. – nneonneo

+0

Tất nhiên, điều này khá khó xảy ra, đó là lý do tại sao tôi có thể sẽ sử dụng giải pháp này.Nhưng, tôi lý tưởng muốn tìm một giải pháp không có vấn đề này. – nneonneo

0

Theo tiêu chuẩn POSIX cho signal(7), longjmp() không phải là một trong các cuộc gọi an toàn để gọi từ bên trong bộ xử lý tín hiệu. Trước khi suy nghĩ về vấn đề này, tài liệu longjmp(3) nói rằng bạn cần đảm bảo mã bạn đang gọi sử dụng sigsetjmp() và siglongjmp()

Nếu mã bạn gọi đang nhảy ra khỏi trình xử lý tín hiệu, thì tôi không 't xem làm thế nào bạn có thể biết khi nào cập nhật biến số recursed của bạn, trừ khi bạn cũng kiểm soát một hàm gọi lại mà mã không xác định này gọi lại vào ứng dụng của bạn.

+0

Chỉ áp dụng cho ** tín hiệu không đồng bộ **. Tôi đang viết một xử lý tín hiệu cho 'SIGSEGV' và các tín hiệu đồng bộ thông thường khác, vì vậy đây không phải là một vấn đề. – nneonneo

Các vấn đề liên quan