NativeScript / NativeScript/ios

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

Offen
#459 1 Kommentar 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Dieses Issue hat noch niemand übernommen.

Vorherrschende Sprache
JavaScript
Sterne
150
Forks
43
Ø Merge
3 T. 10 Std.
Gemergte PRs (30 T.)
22

Beschreibung

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.

Beitragsleitfaden

Beitragsleitfaden öffnen

Erste Schritte

  1. Lies das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreib ins Issue, dass du es übernimmst — das erspart doppelte Arbeit.
  3. Forke das Repository und arbeite in einem Branch.
  4. Öffne einen Pull Request, der die Issue-Nummer nennt.

Rechercherichtung

Beginnen Sie in NativeScript/runtime/Metadata.mm bei MethodMeta::isImplementedInClass und dem Kommentar, der auf dieses Issue verweist; verfolgen Sie die Befüllung von sampleInstances, die Verwendung des mutex und das Re-entrant-Verhalten von alloc. Als erledigt gilt die Aufgabe, wenn verwaiste sample instances während einer Re-entrant- oder konkurrierenden Befüllung beseitigt werden, ohne Deadlocks, unsichere Freigaben oder eine absichtliche dauerhafte Beibehaltung zu verursachen.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
cpp, objective-c
Bereich
mobile-dev
Issue-Typ
Bug
Schwierigkeit
5/5
Geschätzter Aufwand
Über eine Woche
Aktivitätsstatus
Aktiv
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
38/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.