Re: Claude AI code audit of GNUstep core stack — 1 50 fixes, 12 perf optimizations, all available for upstream
Todd White <[email protected]> Mon, 13 Apr 2026 11:37:58 -0400
| Newsgroups | gmane.comp.lib.gnustep.devel |
|---|---|
| Message-ID | <CAAAC8AJ7zDJubucfjQO1xkfm9+_CO0sHOzCABMo-f9Jbn1vhWg@mail.gmail.com> |
--00000000000094bc4e064f5946ab Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Hi David, All good feedback - and certainly pick and choose what you wish to take advantage of / feel is of value. I will go back and look at the comments you made on RB-1, RB-2, etc. and reintegrate those questions into the 2nd pass Claude is making through the code and advise. Cheers, Todd On Mon, Apr 13, 2026 at 11:26=E2=80=AFAM David Chisnall <gnustep@theravensn= est.org> wrote: > Hi, > > Looking at the libobjc2 ones: > > The issue RB-1 is kind-of real, but the fix is incorrect (we should free > the object before calling the unexpected exception handler, because it ma= y > not return), though this is almost unreachable code. It can basically > happen only if there is an internal error in the unwind library. > > RB-2 is not correct, selectors being null is undefined behaviour and > cannot happen in compiler-generated code. Adding a null check on one of > the hottest paths in the runtime would be a regression. > > TS-7 looks like a fix that we need in a few more places, not sure why it= =E2=80=99s > only highlighed in the place the code was copied to, not the place it was > copied from. > > I think TS-14 is spurious, this should not be called twice, the first > caller nulls out the pointer after the cleanup. The one corner case wher= e > it can be called twice is if cleanup *reallocates* the TLS, in which case > doing the cleanup twice is correct. Do you have a test case that > demonstrates this? > > RB-6 looks like the right fix, simple copy-and-paste bug. Note that this > happens only when memory is exhausted, at which point most Objective-C > programs will start failing. > > RB-7, the null check is in a silly place (after the dereference), but the > API contract here is that the argument must not be null, so it=E2=80=99s = actually > dead code. This function also should be setting `*outCount =3D 0` in the > early returns. > > PF-6, yes that refactoring would probably be good to do, though note that > we don=E2=80=99t hit the weak lock in most cases, only if an object is ma= rked as > having weak refs. Have you measured slowdown from this on anything that > *isn=E2=80=99t* a contrived microbenchmark? The quoted slowdown looks in= credibly > unlikely unless you have a microbenchmark doing nothing but hitting weak > references from multiple threads. > > PF-7, this will generate exactly the same code unless we explicitly use a > weaker memory order (both are sequentially consistent by default). We > should move this code over to C++11 atomics at some point. > > TS-3 is incorrect. This counter grows monotonically. If a selector is > registered *while* this call is happening, then the result is undefined. > It=E2=80=99s technically UB, in that there is an unsynchronised read. > > PF-4 was an intentional design choice. Method replacements are > infrequent. The proposed change would make things worse. > > David > > On 13 Apr 2026, at 04:35, Todd White <[email protected]> wrote: > > Hi GNUstep Team, > > As an exercise to test out the latest Claude AI capabilities, we recently > completed a comprehensive, bottom-up code audit of the GNUstep core stack= =E2=80=94 > all seven repositories =E2=80=94 covering libobjc2, libs-base, libs-coreb= ase, > libs-opal, libs-quartzcore, libs-gui, and libs-back. The full results, > documentation, and all fix commits are publicly available at: > > https://github.com/DTW-Thalion/gnustep-audit > > I wanted to share what we found and offer to contribute any or all of the > changes back upstream. > > ## What we did > > We audited the entire stack bottom-up =E2=80=94 runtime through UI layer = =E2=80=94 > examining every file for robustness issues, thread safety gaps, security > vulnerabilities, correctness bugs, and performance bottlenecks. Each > finding was severity-rated, fixed in an atomic commit tagged with a findi= ng > ID, and validated with a dedicated regression test. We also wrote 13 > performance benchmarks with a baseline/compare workflow so improvements c= an > be measured reproducibly. > > ## What we found and fixed > > Across all seven repos, we identified and fixed 150 findings: > > - 22 Critical =E2=80=94 including NSSecureCoding bypass (class whitelist > completely unimplemented), TLS server verification disabled by default, > use-after-free in objc_exception_rethrow, NULL dereferences, data races i= n > CFRunLoop and CATransaction, zero thread safety across the entire libs-ba= ck > backend (189 files, 0 locks), and a swapped sendto() argument in CFSocket > that prevented any data from being sent. > > - 46 High =E2=80=94 deadlocks in property spinlocks, race conditions, buf= fer > overflows (CGContext dash buffer allocated in bytes instead of doubles), > broken APIs, JSON parser with no recursion depth limit (stack overflow > DoS), and integer overflow in binary plist bounds checking. > > - 61 Medium =E2=80=94 thread safety gaps in GSLayoutManager, NSView, and > NSApplication event dispatch; missing input validation; and general > robustness issues. > > - 14 Low + 10 confirmed bugs =E2=80=94 documentation issues, minor optimi= zations, > swapped arguments, wrong variables, and inverted conditions (e.g., TIFF > destination init was inverted, making TIFF writing 100% broken). > > We also implemented 12 targeted performance optimizations, including: > > - 64-way lock striping for weak references (5=E2=80=938=C3=97 concurrent = throughput) > - O(1) LRU linked list for NSCache (replacing an O(n) implementation that > also never evicted) > - Geometric growth for CFArray (O(n) vs O(n=C2=B2) sequential appends) > - X11 expose event coalescing, live resize throttling at 60fps, dirty > region tracking in NSView, DPSimage conversion caching, and stack buffer > allocation in CFRunLoop to eliminate per-iteration malloc > > Benchmark results on MSYS2/ucrt64 show +29=E2=80=9331% for retain/release= , +12=E2=80=9318% > for message dispatch, +46=E2=80=9355% for array operations, and +25% for = NSCache. > > ## How the work is organized > > Each of the seven repos has its own fork under our GitHub org ( > https://github.com/DTW-Thalion) with fix commits on master. The > gnustep-audit repo itself contains: > > - Per-phase findings reports (docs/phase1 through phase6) > - A master audit summary (docs/AUDIT-SUMMARY.md) > - 51 regression tests and 13 benchmarks under instrumentation/ > - A Makefile-driven test and benchmark harness with baseline/compare > support > > All 32 regression tests pass on the patched stack (up from 18/32 on > unpatched). > > ## Offer to contribute upstream > > We'd be happy to contribute any or all of these changes back into the mai= n > GNUstep repositories =E2=80=94 whether as pull requests, individual patch= es, or in > whatever form works best for your workflow. Feel free to help yourself to > the repo. > > The security-critical fixes (NSSecureCoding, TLS defaults, JSON depth > limit, binary plist overflow) and the confirmed crash bugs (use-after-fre= e, > NULL derefs, inverted conditions) are probably the highest-priority > candidates for upstream integration. > > Please feel free to reach out with any questions. We have a lot of respec= t > for the GNUstep project (and a bit nostalgic for heady days of > NeXTStep/OpenStep) and would like to see this work benefit the broader > community. > > It's unclear if the codebase is actively maintained or if many people > still use it, but we hope that this exercise provides some value. > > Best regards, > > Todd > > *Todd White* > Managing Director > > > 177 Huntington Avenue, 17th Floor > Boston, MA 02115 > Telephone: +1 617 237-2835 Ext. 101 > EIN: 33-2228263 > > Website <https://www.thalion.global/> | Twitter/X > <https://x.com/TTIScience> | YouTube <https://www.youtube.com/@TTIScience= > > > [image: > https://app.candid.org/profile/16308928/the-thalion-initiative-us-inc-33-= 2228263/?pkId=3D39bf89e9-f544-478c-a3fe-e157e345181d] > <https://app.candid.org/profile/16308928/the-thalion-initiative-us-inc/?p= kId=3D39bf89e9-f544-478c-a3fe-e157e345181d&isActive=3Dtrue> > > > --00000000000094bc4e064f5946ab Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr"><div class=3D"gmail_default" style=3D"font-family:arial,sa= ns-serif">Hi David,</div><div class=3D"gmail_default" style=3D"font-family:= arial,sans-serif"><br></div><div class=3D"gmail_default" style=3D"font-fami= ly:arial,sans-serif">All good feedback - and certainly pick and choose what= you wish to take advantage of / feel is of value.=C2=A0</div><div class=3D= "gmail_default" style=3D"font-family:arial,sans-serif"><br></div><div class= =3D"gmail_default" style=3D"font-family:arial,sans-serif">I will go back an= d look at the comments you made on RB-1, RB-2, etc. and reintegrate those q= uestions into the 2nd pass Claude is making through the code and advise.</d= iv><div class=3D"gmail_default" style=3D"font-family:arial,sans-serif"><br>= </div><div class=3D"gmail_default" style=3D"font-family:arial,sans-serif">C= heers,</div><div class=3D"gmail_default" style=3D"font-family:arial,sans-se= rif"><br></div><div class=3D"gmail_default" style=3D"font-family:arial,sans= -serif">Todd</div><div class=3D"gmail_default" style=3D"font-family:arial,s= ans-serif"><br></div></div><br><div class=3D"gmail_quote gmail_quote_contai= ner"><div dir=3D"ltr" class=3D"gmail_attr">On Mon, Apr 13, 2026 at 11:26=E2= =80=AFAM David Chisnall <<a href=3D"mailto:[email protected]">gn= [email protected]</a>> wrote:<br></div><blockquote class=3D"gmail_= quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,= 204);padding-left:1ex"><div>Hi,<div><br></div><div>Looking at the libobjc2 = ones:</div><div><br></div><div>The issue RB-1 is kind-of real, but the fix = is incorrect (we should free the object before calling the unexpected excep= tion handler, because it may not return), though this is almost unreachable= code.=C2=A0 It can basically happen only if there is an internal error in = the unwind library.</div><div><br></div><div>RB-2 is not correct, selectors= being null is undefined behaviour and cannot happen in compiler-generated = code.=C2=A0 Adding a null check on one of the hottest paths in the runtime = would be a regression.</div><div><br></div><div>TS-7 looks like a fix that = we need in a few more places, not sure why it=E2=80=99s only highlighed in = the place the code was copied to, not the place it was copied from.</div><d= iv><br></div><div>I think TS-14 is spurious, this should not be called twic= e, the first caller nulls out the pointer after the cleanup.=C2=A0 The one = corner case where it can be called twice is if cleanup *reallocates* the TL= S, in which case doing the cleanup twice is correct.=C2=A0 Do you have a te= st case that demonstrates this?</div><div><br></div><div>RB-6 looks like th= e right fix, simple copy-and-paste bug.=C2=A0 Note that this happens only w= hen memory is exhausted, at which point most Objective-C programs will star= t failing.</div><div><br></div><div>RB-7, the null check is in a silly plac= e (after the dereference), but the API contract here is that the argument m= ust not be null, so it=E2=80=99s actually dead code.=C2=A0 This function al= so should be setting `*outCount =3D 0` in the early returns.</div><div><br>= </div><div>PF-6, yes that refactoring would probably be good to do, though = note that we don=E2=80=99t hit the weak lock in most cases, only if an obje= ct is marked as having weak refs.=C2=A0 Have you measured slowdown from thi= s on anything that *isn=E2=80=99t* a contrived microbenchmark?=C2=A0 The qu= oted slowdown looks incredibly unlikely unless you have a microbenchmark do= ing nothing but hitting weak references from multiple threads.</div><div><b= r></div><div>PF-7, this will generate exactly the same code unless we expli= citly use a weaker memory order (both are sequentially consistent by defaul= t).=C2=A0 We should move this code over to C++11 atomics at some point.</di= v><div><br></div><div>TS-3 is incorrect.=C2=A0 This counter grows monotonic= ally.=C2=A0 If a selector is registered *while* this call is happening, the= n the result is undefined.=C2=A0 It=E2=80=99s technically UB, in that there= is an unsynchronised read.</div><div><br></div><div>PF-4 was an intentiona= l design choice.=C2=A0 Method replacements are infrequent.=C2=A0 The propos= ed change would make things worse.</div><div><br></div><div>David</div><div= ><div><br><blockquote type=3D"cite"><div>On 13 Apr 2026, at 04:35, Todd Whi= te <[email protected]> wrote:</div><br><div><div dir=3D"ltr">= <div><div class=3D"gmail_default" style=3D"font-family:arial,sans-serif"><s= pan style=3D"font-family:Arial,Helvetica,sans-serif">Hi GNUstep Team,</span= ></div><br><span class=3D"gmail_default" style=3D"font-family:arial,sans-se= rif">As an exercise to test out the latest Claude AI capabilities, w</span>= e recently completed a comprehensive, bottom-up code audit of the GNUstep c= ore stack =E2=80=94 <span class=3D"gmail_default" style=3D"font-family:aria= l,sans-serif">all=C2=A0</span>seven repositories =E2=80=94 covering libobjc= 2, libs-base, libs-corebase, libs-opal, libs-quartzcore, libs-gui, and libs= -back. The full results, documentation, and all fix commits are publicly av= ailable at:<br><br><a href=3D"https://github.com/DTW-Thalion/gnustep-audit"= target=3D"_blank">https://github.com/DTW-Thalion/gnustep-audit</a><br><br>= I wanted to share what we found and offer to contribute any or all of the c= hanges back upstream.<br><br>## What we did<br><br>We audited the entire st= ack bottom-up =E2=80=94 runtime through UI layer =E2=80=94 examining every = file for robustness issues, thread safety gaps, security vulnerabilities, c= orrectness bugs, and performance bottlenecks. Each finding was severity-rat= ed, fixed in an atomic commit tagged with a finding ID, and validated with = a dedicated regression test. We also wrote 13 performance benchmarks with a= baseline/compare workflow so improvements can be measured reproducibly.<br= ><br>## What we found and fixed<br><br>Across all seven repos, we identifie= d and fixed 150 findings:<br><br>- 22 Critical =E2=80=94 including NSSecure= Coding bypass (class whitelist completely unimplemented), TLS server verifi= cation disabled by default, use-after-free in objc_exception_rethrow, NULL = dereferences, data races in CFRunLoop and CATransaction, zero thread safety= across the entire libs-back backend (189 files, 0 locks), and a swapped se= ndto() argument in CFSocket that prevented any data from being sent.<br><br= >- 46 High =E2=80=94 deadlocks in property spinlocks, race conditions, buff= er overflows (CGContext dash buffer allocated in bytes instead of doubles),= broken APIs, JSON parser with no recursion depth limit (stack overflow DoS= ), and integer overflow in binary plist bounds checking.<br><br>- 61 Medium= =E2=80=94 thread safety gaps in GSLayoutManager, NSView, and NSApplication= event dispatch; missing input validation; and general robustness issues.<b= r><br>- 14 Low + 10 confirmed bugs =E2=80=94 documentation issues, minor op= timizations, swapped arguments, wrong variables, and inverted conditions (e= .g., TIFF destination init was inverted, making TIFF writing 100% broken).<= br><br>We also implemented 12 targeted performance optimizations, including= :<br><br>- 64-way lock striping for weak references (5=E2=80=938=C3=97 conc= urrent throughput)<br>- O(1) LRU linked list for NSCache (replacing an O(n)= implementation that also never evicted)<br>- Geometric growth for CFArray = (O(n) vs O(n=C2=B2) sequential appends)<br>- X11 expose event coalescing, l= ive resize throttling at 60fps, dirty region tracking in NSView, DPSimage c= onversion caching, and stack buffer allocation in CFRunLoop to eliminate pe= r-iteration malloc<br><br>Benchmark results on MSYS2/ucrt64 show +29=E2=80= =9331% for retain/release, +12=E2=80=9318% for message dispatch, +46=E2=80= =9355% for array operations, and +25% for NSCache.<br><br>## How the work i= s organized<br><br>Each of the seven repos has its own fork under our GitHu= b org (<a href=3D"https://github.com/DTW-Thalion" target=3D"_blank">https:/= /github.com/DTW-Thalion</a>) with fix commits on master. The gnustep-audit = repo itself contains:<br><br>- Per-phase findings reports (docs/phase1 thro= ugh phase6)<br>- A master audit summary (docs/AUDIT-SUMMARY.md)<br>- 51 reg= ression tests and 13 benchmarks under instrumentation/<br>- A Makefile-driv= en test and benchmark harness with baseline/compare support<br><br>All 32 r= egression tests pass on the patched stack (up from 18/32 on unpatched).<br>= <br>## Offer to contribute upstream<br><br>We'd be happy to contribute = any or all of these changes back into the main GNUstep repositories =E2=80= =94 whether as pull requests, individual patches, or in whatever form works= best for your workflow.=C2=A0<span class=3D"gmail_default" style=3D"font-f= amily:arial,sans-serif">Feel free to help yourself to the repo.</span><br><= br>The security-critical fixes (NSSecureCoding, TLS defaults, JSON depth li= mit, binary plist overflow) and the confirmed crash bugs (use-after-free, N= ULL derefs, inverted conditions) are probably the highest-priority candidat= es for upstream integration<span class=3D"gmail_default" style=3D"font-fami= ly:arial,sans-serif">.</span><br><br>Please feel free to reach out with any= questions. We have a lot of respect for the GNUstep project <span class=3D= "gmail_default" style=3D"font-family:arial,sans-serif">(and a bit nostalgic= for heady days of NeXTStep/OpenStep)=C2=A0</span>and would like to see thi= s work benefit the broader community.</div><div><br></div><div><div class= =3D"gmail_default" style=3D"font-family:arial,sans-serif">It's unclear = if the codebase is actively maintained or if many people still use it, but = we hope that this exercise provides some value.</div><br>Best regards,</div= ><div><br></div><div><div class=3D"gmail_default" style=3D"font-family:aria= l,sans-serif">Todd</div><br clear=3D"all"></div><div><div dir=3D"ltr" class= =3D"gmail_signature"><div dir=3D"ltr"><b>Todd White</b><div>Managing Direct= or</div><div><br></div><div></div><div><img src=3D"https://ci3.googleuserco= ntent.com/mail-sig/AIorK4xw08RqGgDKsHOD8XqEYb6-GgGIJIf1cRrXVWqgRb0R08UESMvM= dTT1W33NqQlLRUIicyduuegMbbIF" width=3D"96" height=3D"71"><br></div><div>177= Huntington Avenue, 17th Floor</div><div>Boston, MA 02115</div><div>Telepho= ne: +1 617 237-2835 Ext. 101</div><div>EIN: 33-2228263</div><div><br></div>= <div><a href=3D"https://www.thalion.global/" target=3D"_blank">Website</a>= =C2=A0| <a href=3D"https://x.com/TTIScience" target=3D"_blank">Twitter/X</a= >=C2=A0| <a href=3D"https://www.youtube.com/@TTIScience" target=3D"_blank">= YouTube</a></div><div><br></div><div><a href=3D"https://app.candid.org/prof= ile/16308928/the-thalion-initiative-us-inc/?pkId=3D39bf89e9-f544-478c-a3fe-= e157e345181d&isActive=3Dtrue" target=3D"_blank"><img src=3D"https://cdn= .candid.org/seals-of-transparency/2026/candid-seal-gold-2026.png" width=3D"= 96" height=3D"96" alt=3D"https://app.candid.org/profile/16308928/the-thalio= n-initiative-us-inc-33-2228263/?pkId=3D39bf89e9-f544-478c-a3fe-e157e345181d= "></a><br></div></div></div></div></div> </div></blockquote></div><br></div></div></blockquote></div> --00000000000094bc4e064f5946ab--