Repository navigation
Keep a certificate alive while one of its times is in use - #110
Merged
Merged
Conversation
`cert.time_not_before` and `cert.time_not_after` return an Asn1Time that
points into the certificate (X509_getm_notBefore/notAfter), but it held no
reference to it. Once the certificate was collected, the time read freed
memory: `X509Certificate(pem).time_not_after` printed after a collection
failed every time (200 of 200), and freeing such a time freed the
certificate's own, which the certificate freed again later (the test
process aborts on main).
Asn1Time gets an `owner` field. The getters set it to a certificate
wrapper with its own reference (X509_up_ref), so neither collecting nor
explicitly freeing the original certificate frees the time, and `free` on
such a time drops that reference instead of freeing the time. Adjusting
it still changes the certificate's time, as the tests and helpers rely on.
With the extra field the struct no longer passes to C as a bare pointer,
so the ccalls take `Ptr{Cvoid}` through `unsafe_convert`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #110 +/- ##
==========================================
+ Coverage 83.07% 83.08% +0.01%
==========================================
Files 2 2
Lines 1341 1342 +1
==========================================
+ Hits 1114 1115 +1
Misses 227 227 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
cert.time_not_beforeandcert.time_not_afterreturn anAsn1Timethat points into the certificate (X509_getm_notBefore/notAfter), with no reference to the certificate. When the certificate is collected first, the time points at freed memory:Separately,
free(t)on such a time freed the certificate's ownASN1_TIME, whichX509_freelater frees again.Fix
Asn1Timegets anownerfield. The two getters set it to a newX509Certificatewrapper holding its own reference (X509_up_ref). The certificate then stays alive while the time is in use, even if the original wrapper is collected or freed explicitly.freeon such a time drops that reference and leaves the time to the certificate.Dates.adjust(cert.time_not_after, Year(1))still changes the certificate in place. The tests andtest/http_helpers.jlrely on that.Asn1Timenow declarePtr{Cvoid}and use aBase.unsafe_convertmethod; ccall keeps the object rooted during the call.Verification
CertificateTimeKeepsCertificatecovers:GC.gc(true), 20 rounds;free(cert);free(time)followed by reading the certificate's time;main, the suite with only the new test aborts: signal 6, the double free. With the fix, all 24 checks pass.X509Certificate(pem).time_not_afterafter a collection.main: wrong 200 of 200 times withMallocScribble=1, and 500 of 500 without it while other certificates are parsed.-t 4: passes.Self-review
OpenSSL.Asn1Timeby value in its ownccallwould now pass a two-field struct. A GitHub code search forAsn1Timein Julia code finds only copies of this package. Every ccall in the package that took it is converted.Asn1Time(ptr)(no owner, no finalizer) behaves as before. Owned times (Asn1Time(),Asn1Time(::Int),Asn1Time(::DateTime)) still have their finalizer, andfreefrees them as before. The existingAsn1Timetestset, which frees twice, passes.C_NULL: the getters throw on a NULL time.adjuston a freed view allocates a new time, as before.X509_up_ref. These are not hot paths.🤖 Generated with Claude Code