Skip to content

Race condition when populating the ObjCClass method/attribute cache #252

@freakboy3742

Description

@freakboy3742

Describe the bug

ObjCClass maintains a cache of ObjC method/property references. This cache is populated on first use.

If you have multiple threads using the same Objective C class, there is a potential race condition. If the first thread tries to access a method or property, it will detect that the cache is empty, and attempt to populate it.

ObjCClass._load_methods() involves an iteration over all methods in the class, and over all methods in the superclasses, adding methods to the method cache as they are discovered.

If thread 1 attempts to invoke a method, and discovers the method cache is empty, it will begin to load the method cache. However, this puts the method cache into a state where it no longer appears to be unpopulated; so if a second thread attempts to access a any method on the same class, it will discover an apparently populated cache, and use that cache to access the method. If the method hasn't been populated by the first thread, the second thread will get an AttributeError, even though the attribute is actually valid.

Steps to reproduce

Run the Toga GUI test case on macOS or iOS (currently in the macos-probe branch). This problem manifests infrequently - maybe every ~50 executions.

Expected behavior

Attribute access should be reliable and idempotent.

Screenshots

No response

Environment

  • Operating System: macOS, iOS
  • Python version: All
  • Software versions:
    • Briefcase: 0.3.12+
    • Toga: 0.3.12+

Logs

I haven't got an example to hand - but it always manifests as a vanilla AttributeError on an attribute that should exist.

Additional context

Discovered while testing beeware/toga#1707.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugA crash or error in behavior.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions