Fix memory leaks (#616)#816
Conversation
|
@objective-see, when you get a chance, I'd appreciate your review. |
|
@objective-see, any chance you've had some time to review? |
|
I have tried to unsubscribe from,lulu for the last 5 years and nothing
works. I have no idea what it is , no interest’….delete unsubscribe please
or now or maybe or else
Sent from jt.
…On Wed, 7 Jan 2569 BE at 08:21 Jonathan Hult ***@***.***> wrote:
*jhult* left a comment (objective-see/LuLu#816)
<#816 (comment)>
@objective-see <https://github.com/objective-see>, any chance you've had
some time to review?
—
Reply to this email directly, view it on GitHub
<#816 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AB3VSHFDCZ5JN2VRLMWVYMD4FRNSPAVCNFSM6AAAAACPDYOLDGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTOMJWHE2DOOBUHA>
.
You are receiving this because you are subscribed to this thread.Message
ID: ***@***.***>
|
|
Please do so. May be something I thought of interest.
Sent from jt.
…On Wed, 7 Jan 2569 BE at 14:21 Objective-See Foundation < ***@***.***> wrote:
*objective-see* left a comment (objective-see/LuLu#816)
<#816 (comment)>
@jhult <https://github.com/jhult>: thanks will take a look ASAP!
@j-tamad <https://github.com/j-tamad>: If I view your profile, I can see
you're following Objective-See (I clicked on "following"):
Screenshot.2026-01-06.at.21.17.14.png (view on web)
<https://github.com/user-attachments/assets/cf211ab2-0fc4-4353-b0d9-15031d6ab0cb>
Screenshot.2026-01-06.at.21.17.25.png (view on web)
<https://github.com/user-attachments/assets/b78a0ecb-16cc-4164-bf39-6198836f6761>
I'd start by unfollowing, as maybe that'd "unsubscribe" you?
—
Reply to this email directly, view it on GitHub
<#816 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AB3VSHHFI62QKMSAKAOXR734FSXXRAVCNFSM6AAAAACPDYOLDGVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTOMJXGYZTEOBRGY>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
|
@j-tamad you have to unfollow! It's not something I can do 🙈 |
|
@objective-see, did you get a chance to review? |
|
Thanks for the PR 🙏🏽 For example, related flows are only saved when an alert (for the same process is successfully delivered to the user). When they response, all related flows are removed and then handled. So even if the handling fails, the flow has been removed (freed). So the whole Also, saving all pending flows (to resume if extension is shutting down), actually increased the memory footprint. An I'm really ok in the (rare) case the user shutdowns the extension that any paused flows are then terminated (i.e. current logic seems fine). I also asked Claude about retaining self in the alert blocks and it told me the current code is fine 🤷♂️ I'll spend more time looking through this though! P.S. if you disable SIP and AMFI you should be able to build the extension yourself (if you have a Developer ID). |
Related flows were removed from the tracking array but never resumed via resumeFlow:withVerdict:, causing them to stay paused indefinitely and leak memory. Fixes objective-see#616
a0b3463 to
ead1dab
Compare
|
My initial commit in this PR was over-engineered (and was in fact written by AI). Here's a focused replacement (also written by AI).
The actual bug is in For chatty processes (e.g. browsers, VPN clients), dozens or hundreds of related flows queue up while the user decides. Every one of them leaks. Over hours/days this reaches gigabytes. For chatty processes (browsers, VPN clients), this means hundreds of leaked flows per alert interaction.
Correct. With the actual bug fixed, flows are properly resumed when the user responds, so there's nothing to clean up.
Correct. Removed entirely.
Agreed. The XPC framework owns the block, not The fixOne method changed: flow = flows[i];
verdict = [self processEvent:flow]; // get verdict first
if([NEFilterNewFlowVerdict pauseVerdict] == verdict)
{
break; // new alert shown, wait for user
}
[self resumeFlow:flow withVerdict:verdict]; // resume the paused flow
[flows removeObjectAtIndex:i]; // then remove from trackingAlso cleans up empty entries from What this does NOT change
|
There was a problem hiding this comment.
Thanks! This looks great, save for one (potential?) issue.
I think the code should use isEqual: instead of ==:
Fix:
verdict = [self processEvent:flow];
if([verdict isEqual:[NEFilterNewFlowVerdict pauseVerdict]])
Otherwise I think == is just doing a pointer comparison (unless Apple's implementation does return a singleton for pauseVerdict, which would make == work in practice). Either way isEqual: is the safer/"correct" approach (this was wrong in the original code too)
|
Now in latest release: @jhult if you continue to see memory issues, please let me know! I have a bit more time on my hands these days for fixes 🙏🏽 |


Fix Memory Leaks in System Extension
Fixes #616, where 1+ memory leak(s) in the system extension could cause memory to grow from ~100 MB to 10+ GB, causing network failures.
Note: This was largerly generated by Claude. I ran many passes to try to get the best possible outcome. However, since I can't sign the extension and can't test, I can't vouch for whether this actually works (or is even the proper approach).
Problem
The system extension accumulates memory over time (versions 2.4.3 - 3.1.5), eventually consuming 10+ GB RAM and breaking network connectivity.
Root causes
pendingAlerts/relatedFlowsdictionariesprocessRelatedFlow)Solution
Break Retain Cycles
A. Use weak-strong dance pattern in alert reply blocks
B. Prevents self from being retained by async XPC callbacks
Track All Flows
A. Add
pendingAlertsdictionary to track flows awaiting user responseB. Ensures flows aren't lost when user doesn't respond
Fix processRelatedFlow Bug
A. Resume flows BEFORE removing from dictionary
B. Handle pause verdict correctly (keep in dictionary for next round)
Cleanup Orphaned Flows
A. Add
isFlowOrphanedhelper andcleanupOrphanedFlowsmethodB. Resume orphaned flows with
dropVerdict(critical for system to release)C. Triggers: every 5 minutes + on XPC failure
Dealloc Cleanup
A. Resume all flows during dealloc using
resumeFlowshelperB. Prevents flows from remaining paused on extension shutdown
Race Condition Prevention
A. Check if flow still in
pendingAlertsbefore processing user responseB. Prevents double-resume if cleanup already handled flow
C. Ensures user's choice isn't applied to stale flows
All flow resume operations use shared
resumeFlowshelper to eliminate code duplication and ensure consistent error handling.Testing
Unit tests
Run tests:
cd LuLu/Tests && bash run_tests.shIntegration testing
Requires system extension runtime (which I can't sign and thus cannot run/test).
Expected behavior
Edge Cases Handled
@synchronized)