Skip to content

Fix KVO bugs related to cyclical observer dependencies (#608)#612

Merged
rfm merged 3 commits into
gnustep:masterfrom
HendrikHuebner:kvo-bug
May 23, 2026
Merged

Fix KVO bugs related to cyclical observer dependencies (#608)#612
rfm merged 3 commits into
gnustep:masterfrom
HendrikHuebner:kvo-bug

Conversation

@HendrikHuebner
Copy link
Copy Markdown
Contributor

This PR solves two KVO bugs described in #608.

I used the suggested solution from the original issue, while keying the nodes using the object pointer and the key name.

Additionally, I added a bunch of tests here. These are essentially fuzzing attempts by an LLM and have been very useful counter examples for why previous approaches I tried locally didn't work. I compared the results of running each of these against Apple's objc implementation and the behavior now matches Apple.

Let me know if the tests should be kept and whether I should add a change log entry.

- Replaced fragile dependent-keypath visited tracking with node keys `(object pointer, key name)` in dependency expansion.
- Added explicit ancestor/on-stack tracking to distinguish true cycles from safe revisits
- On revisit:
  - if node is on ancestor stack: treat as cycle and stop expansion
  - if visited but not on stack: allow expansion to continue
- This prevents infinite recursive rebuilds on cyclic dependencies while preserving correct branch wiring after nil-to-non-nil rematerialization and shared-path alias cases.
@HendrikHuebner HendrikHuebner requested a review from rfm as a code owner May 12, 2026 16:30
@HendrikHuebner
Copy link
Copy Markdown
Contributor Author

@rmf the tests fail for gcc. I suppose they are using the old KVO implementation. Should I just skip them for gcc?

@rfm
Copy link
Copy Markdown
Contributor

rfm commented May 13, 2026

Tests are great, so we prefer not to disable them if possible.
The mechanism to deal with cases where our implementation is not yet portable is to mark the testcase that don't yet pass as 'hopes'.
That's done using the testHopeful flag.

eg.
#if !defined(clang)
testHopeful = YES;
#endif
// testcases here
#if !defined(clang)
testHopeful = NO;
#endif

That will run the tests, but report them as dashed hopes rather than failures, so the testsuite as a whole passes but reminds us there is work to be done on the portability.

@HendrikHuebner
Copy link
Copy Markdown
Contributor Author

@rfm Can you take another look? @triplef you have tested this patch as well, right?

@triplef
Copy link
Copy Markdown
Member

triplef commented May 18, 2026

Yes, I tested it on Android with our app. 👍

Copy link
Copy Markdown
Contributor

@rfm rfm left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks. Looks good.

@rfm rfm merged commit 7a59909 into gnustep:master May 23, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants