Làm thế nào để kiểm tra, giới hạn nào đã vượt quá? (Quá trình chấm dứt vì ulimit.)


11

Giả sử quy trình chạy trong môi trường giới hạn:

(
ulimit  ... -v ... -t ... -x 0 ...
./program
)

Chương trình bị chấm dứt.

Có thể có nhiều lý do: vượt quá giới hạn bộ nhớ / thời gian / tệp; chỉ cần segfault đơn giản; hoặc thậm chí chấm dứt bình thường với mã trả về 0.

Làm thế nào để kiểm tra lý do chấm dứt chương trình, mà không sửa đổi chương trình là gì?

PS Tôi có nghĩa là "khi nhị phân được đưa ra". Có lẽ một số trình bao bọc (ptrace-ing, vv) có thể giúp đỡ?

Câu trả lời:


6

Nói chung, tôi không nghĩ bạn có thể không may. (Một số hệ điều hành có thể cung cấp cho nó, nhưng tôi không biết những cái tôi biết hỗ trợ này.)

Tài liệu tham khảo cho giới hạn tài nguyên: getrlimittừ POSIX 2008.

Lấy ví dụ về giới hạn CPU RLIMIT_CPU.

  • Nếu quá trình vượt quá giới hạn mềm, nó sẽ được gửi SIGXCPU
  • Nếu quá trình vượt quá giới hạn cứng, nó sẽ trở nên đơn giản SIGKILL

Nếu bạn có thể wait()trong chương trình của mình, bạn có thể biết nếu nó bị giết bởi SIGXCPU. Nhưng bạn không thể phân biệt được một người được SIGKILLphái đi vì vi phạm giới hạn cứng từ một vụ giết người cũ đơn giản từ bên ngoài. Hơn nữa, nếu chương trình xử lý XCPU, bạn thậm chí sẽ không nhìn thấy điều đó từ bên ngoài.

Điều tương tự cho RLIMIT_FSIZE. Bạn có thể thấy SIGXFSZtừ wait()trạng thái nếu chương trình không xử lý nó. Nhưng một khi vượt quá giới hạn kích thước tệp, điều duy nhất xảy ra là I / O tiếp tục thử kiểm tra giới hạn đó một lần nữa sẽ nhận được EFBIG- điều này sẽ bị chương trình xử lý (hoặc không, không may). Nếu chương trình xử lý SIGXFSZ, giống như trên - bạn sẽ không biết về nó.

RLIMIT_NOFILE? Chà, bạn thậm chí không nhận được tín hiệu. openvà bạn bè chỉ cần quay lại EMFILEchương trình. Nó không bị làm phiền, vì vậy nó sẽ thất bại (hoặc không) theo bất kỳ cách nào nó được mã hóa để thất bại trong tình huống đó.

RLIMIT_STACK? Tốt cũ SIGSEGV, không thể được phân biệt với điểm số của các lý do khác để được giao một. (Bạn sẽ biết rằng đó là những gì đã giết quá trình, mặc dù, từ waittrạng thái.)

RLIMIT_ASRLIMIT_DATAsẽ chỉ thực hiện malloc()và một vài người khác bắt đầu thất bại (hoặc nhận SIGSEGVnếu giới hạn AS bị tấn công trong khi cố gắng mở rộng ngăn xếp trên Linux). Trừ khi chương trình được viết rất tốt, có thể nó sẽ thất bại khá ngẫu nhiên vào thời điểm đó.

Vì vậy, nói tóm lại, các lỗi này không khác biệt rõ ràng với các lý do tử vong của quá trình khác, vì vậy bạn không thể chắc chắn hoặc có thể được xử lý hoàn toàn từ chương trình trong trường hợp nó quyết định nếu / khi / cách thức tiến hành, không phải bạn từ bên ngoài.

Điều tốt nhất bạn có thể làm theo như tôi biết là viết một chút mã cho chương trình của bạn, chờ đợi trên đó và:

  • kiểm tra trạng thái thoát để phát hiện SIGXCPUSIGXFSZ(AFAIK, các tín hiệu đó sẽ chỉ được HĐH tạo ra cho các vấn đề giới hạn tài nguyên). Tùy thuộc vào nhu cầu chính xác của bạn, bạn có thể cho rằng điều đó SIGKILLSIGSEGVcũng liên quan đến giới hạn tài nguyên, nhưng đó là một chút khó khăn.
  • nhìn vào những gì bạn có thể nhận được từ getrusage(RUSAGE_CHILDREN,...)việc triển khai của bạn để có gợi ý về những thứ khác.

Các cơ sở dành riêng cho hệ điều hành có thể tồn tại để trợ giúp ở đây (có thể là những thứ như ptracetrên Linux, hoặc Solaris dtrace), hoặc có thể là các kỹ thuật loại trình gỡ lỗi, nhưng điều đó sẽ còn gắn chặt hơn với việc triển khai cụ thể của bạn.


(Tôi hy vọng người khác sẽ trả lời bằng một số điều kỳ diệu mà tôi hoàn toàn không biết.)


Đồng ý. Điều gì về chỉ ba điều đó: (Mem) vượt quá giới hạn bộ nhớ, (Thời gian) giới hạn thời gian, (Err) lỗi khác? Tôi biết về cách tạo trình bao bọc xung quanh mallocnhưng thật không may, nó không giải quyết được vấn đề bộ nhớ nói chung, vì nói chung đó là về cuộc gọi hệ thống brk(tôi có đúng không?).
Grzegorz Wierzowiecki

1
Gói malloc sẽ không giúp đỡ nếu bạn không kiểm soát chương trình. Nếu bạn đang nói về hacks như LD_PRELOADing đường biên giới mà cho "không điều chỉnh quá trình" chế của bạn, và nó sẽ giúp một chút, nhưng không thực sự - malloc, brk, sbrkmmapsẽ thất bại với ENOMEM, chính xác như nếu bạn thực sự đang ở trong một tình huống bộ nhớ thấp (nhưng thấp hơn giới hạn bộ nhớ). Giới hạn thời gian là RLIMIT_CPU, tôi không biết giới hạn thời gian trên đồng hồ treo tường.
Mat

Cảm ơn đã đảm bảo cho tôi về brk. Như tôi thấy, chương trình yêu cầu 'không xử lý các tín hiệu X, Y, Z ...' sẽ giải quyết các vấn đề của SIGXCPU, SIGXFSZ, SIGSEGV, nhờ Waitpid (Nếu tôi sai, vui lòng sửa lại cho tôi).
Grzegorz Wierzowiecki

1
SIGSEGV có thể được nêu ra trong các tình huống không phải là vi phạm giới hạn tài nguyên (sự vô tình của con trỏ null là điều phổ biến nhất làm tăng nó) - bạn không thể chắc chắn rằng một cú đánh ulimit gây ra nó.
Mat

Cảm ơn đã đảm bảo cho tôi về brk. Như tôi thấy, chương trình yêu cầu 'không xử lý các tín hiệu X, Y, Z ...' sẽ giải quyết các vấn đề của SIGXCPU, SIGXFSZ, SIGSEGV, nhờ Waitpid. Tôi có đúng không
Grzegorz Wierzowiecki

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.