isImplementedInClass leaks the losing sample instance on re-entrant or racing cache population

Đang mở
#459 1 bình luận 0 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

Đánh giá

Độ khó
5/5
Thời gian dự kiến
Hơn một tuần
Mức phù hợp với người mới
38/100
Loại issue
Lỗi
Độ rõ ràng
Khá rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
cpp, objective-c
Lĩnh vực
mobile-dev

Hướng nghiên cứu

Bắt đầu trong NativeScript/runtime/Metadata.mm tại MethodMeta::isImplementedInClass và phần chú thích trỏ đến issue này; theo dõi việc tạo sampleInstances, cách sử dụng mutex và hành vi re-entrant của alloc. Hoàn thành nghĩa là loại bỏ các sample instances bị bỏ lại trong quá trình tạo re-entrant hoặc tạo có cạnh tranh mà không gây deadlock, giải phóng không an toàn hoặc giữ lại vĩnh viễn một cách có chủ đích.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

Problem

MethodMeta::isImplementedInClass (NativeScript/runtime/Metadata.mm) keeps a process-wide cache of [klass alloc]-created sample instances used to answer respondsToSelector: for classes whose alloc returns a different class or which forward messages. The cache is populated like this:

  1. [klass alloc] runs outside the mutex — deliberately, because alloc can trigger +initialize, which may run arbitrary code that re-enters this method (holding the lock would deadlock).
  2. The lock is then taken and sampleInstances.emplace(klass, instance) inserts.

When the emplace loses — the re-entrant call already populated the entry for the same class, or another thread raced — the freshly allocated instance is abandoned: one leaked object per lost race (Instruments shows these as e.g. a leaked UIAlertView / NSURLSessionConfiguration attributed to isImplementedInClass). The count varies run to run since it is timing-dependent.

Why the obvious fixes don't work

  • Releasing the loser is unsafe: the instance is alloc'd but never init'd, so -release runs -dealloc against zero-filled ivars of an arbitrary framework class, on whatever thread the probe ran on (it demonstrably runs on worker threads). Benign for most classes, but a -dealloc that does CFRelease/dispatch_release on a zero ivar traps, and UIKit teardown off the main thread is asserting territory.
  • Holding the lock across alloc deadlocks via the +initialize re-entry described above.
  • Parking losers in a static container merely converts the unreachable leak into intentional perpetual retention — it silences Instruments without reclaiming anything (tried and reverted in #458).

Potential solutions

  • A re-entrancy-aware locking scheme (recursive mutex, or a reader/writer arrangement) so the populate path can be made atomic with respect to re-entrant probes without deadlocking through +initialize.
  • Reuse already-alloc-ed objects: when a sample for that Class is requested (or something else calls [thatClass alloc] through the runtime), hand out / consume the cached instance instead of allocating another, so a losing instance gets used rather than abandoned.

The leak site carries a comment pointing at this issue.

Ngôn ngữ chính
JavaScript
Star
150
Fork
43
Merge trung bình
3 ngày 10 giờ
Pull request đã merge (30 ngày)
22

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của NativeScript/ios

Tất cả issue của NativeScript/ios

Issue tương tự

Thêm issue về JavaScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.