Skip to content

Commit 7ebc52e

Browse files
fix: leaks (#96)
1 parent 186ec5b commit 7ebc52e

5 files changed

Lines changed: 43 additions & 5 deletions

File tree

lsquic/certificates.nim

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,19 @@ proc getCertChain*(chain: ptr struct_stack_st_X509): seq[seq[byte]] =
3737

3838
return output
3939

40+
proc freeCertChain*(chain: ptr struct_stack_st_X509) {.raises: [].} =
41+
## Frees chains returned by lsquic_conn_get_*_cert_chain.
42+
if chain.isNil:
43+
return
44+
45+
let stack = cast[ptr OPENSSL_STACK](chain)
46+
let x509num = OPENSSL_sk_num(stack)
47+
for i in 0 ..< x509num:
48+
let cert = cast[ptr X509](OPENSSL_sk_value(stack, csize_t(i)))
49+
if not cert.isNil:
50+
X509_free(cert)
51+
52+
OPENSSL_sk_free(stack)
53+
4054
proc getFullCertChain*(ssl: ptr SSL): seq[seq[byte]] =
4155
SSL_get_peer_full_cert_chain(ssl).getCertChain()

lsquic/context/client.nim

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ proc onHandshakeDone(
3737
else:
3838
let x509chain = lsquic_conn_get_full_cert_chain(quicClientConn.lsquicConn)
3939
let certChain = x509chain.getCertChain()
40-
OPENSSL_sk_free(cast[ptr OPENSSL_STACK](x509chain))
40+
x509chain.freeCertChain()
4141
quicClientConn.certChain = certChain
4242

4343
quicClientConn.connectedFut.complete()
@@ -60,7 +60,9 @@ proc onConnClosed(conn: ptr lsquic_conn_t) {.cdecl.} =
6060
)
6161
quicClientConn.cancelPending()
6262
quicClientConn.onClose()
63+
quicClientConn.onClose = nil
6364
quicClientConn.lsquicConn = nil
65+
quicClientConn.connectedFut = nil
6466
GC_unref(quicClientConn)
6567
lsquic_conn_set_ctx(conn, nil)
6668

@@ -167,6 +169,7 @@ proc new*(T: typedesc[ClientContext], tlsConfig: TLSConfig): Result[T, string] =
167169

168170
ctx.engine = lsquic_engine_new(0, addr ctx.api)
169171
if ctx.engine.isNil:
172+
ctx.destroy()
170173
return err("failed to create lsquic engine")
171174

172175
ctx.tickTimeout = newTimeout(

lsquic/context/context.nim

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -276,7 +276,7 @@ proc verifyCertificate(
276276
return ssl_verify_invalid
277277

278278
proc setupSSLContext*(quicCtx: QuicContext) =
279-
let sslCtx = SSL_CTX_new(
279+
var sslCtx = SSL_CTX_new(
280280
if quicCtx is ServerContext:
281281
TLS_server_method()
282282
else:
@@ -285,6 +285,12 @@ proc setupSSLContext*(quicCtx: QuicContext) =
285285
if sslCtx.isNil:
286286
raiseAssert "failed to create sslCtx"
287287

288+
var sslCtxInstalled = false
289+
defer:
290+
if not sslCtxInstalled and not sslCtx.isNil:
291+
SSL_CTX_free(sslCtx)
292+
sslCtx = nil
293+
288294
if SSL_CTX_set_ex_data(sslCtx, SSL_CTX_ID, cast[pointer](quicCtx)) != 1:
289295
raiseAssert "could not set data in sslCtx"
290296

@@ -296,13 +302,13 @@ proc setupSSLContext*(quicCtx: QuicContext) =
296302
if quicCtx.tlsConfig.key.len != 0 and quicCtx.tlsConfig.certificate.len != 0:
297303
let pkey = quicCtx.tlsConfig.key.toPKey().valueOr:
298304
raiseAssert "could not convert certificate to pkey: " & error
305+
defer:
306+
EVP_PKEY_free(pkey)
299307

300308
let cert = quicCtx.tlsConfig.certificate.toX509().valueOr:
301309
raiseAssert "could not convert certificate to x509: " & error
302-
303310
defer:
304311
X509_free(cert)
305-
EVP_PKEY_free(pkey)
306312

307313
if SSL_CTX_use_certificate(sslCtx, cert) != 1:
308314
raiseAssert "could not use certificate"
@@ -335,6 +341,7 @@ proc setupSSLContext*(quicCtx: QuicContext) =
335341
discard SSL_CTX_set_max_proto_version(sslCtx, TLS1_3_VERSION)
336342

337343
quicCtx.sslCtx = sslCtx
344+
sslCtxInstalled = true
338345

339346
proc getSSLCtx*(peer_ctx: pointer, sockaddr: ptr SockAddr): ptr SSL_CTX {.cdecl.} =
340347
let quicCtx = cast[QuicContext](peer_ctx)

lsquic/context/server.nim

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ proc onNewConn(
2020

2121
let x509chain = lsquic_conn_get_full_cert_chain(conn)
2222
let certChain = x509chain.getCertChain()
23-
OPENSSL_sk_free(cast[ptr OPENSSL_STACK](x509chain))
23+
x509chain.freeCertChain()
2424

2525
# TODO: should use a constructor
2626
let quicConn = QuicConnection(
@@ -46,6 +46,7 @@ proc onConnClosed(conn: ptr lsquic_conn_t) {.cdecl.} =
4646
let quicConn = cast[QuicConnection](conn_ctx)
4747
quicConn.cancelPending()
4848
quicConn.onClose()
49+
quicConn.onClose = nil
4950
quicConn.lsquicConn = nil
5051
GC_unref(quicConn)
5152
lsquic_conn_set_ctx(conn, nil)
@@ -101,6 +102,7 @@ proc new*(T: typedesc[ServerContext], tlsConfig: TLSConfig): Result[T, string] =
101102

102103
ctx.engine = lsquic_engine_new(LSENG_SERVER, addr ctx.api)
103104
if ctx.engine.isNil:
105+
ctx.destroy()
104106
return err("failed to create lsquic engine")
105107

106108
ctx.tickTimeout = newTimeout(

lsquic/endpoint.nim

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,21 @@ proc new*(
167167
)
168168
endpoint.udp = endpoint.createUdp(address)
169169

170+
var initialized = false
171+
172+
defer:
173+
if not initialized:
174+
if not endpoint.serverContext.isNil:
175+
endpoint.serverContext.destroy()
176+
if not endpoint.clientContext.isNil:
177+
endpoint.clientContext.destroy()
178+
if not endpoint.udp.isNil:
179+
endpoint.udp.close()
180+
170181
if CanListen in capabilities:
171182
endpoint.serverContext = createServerContext(tlsConfig, cint(endpoint.udp.fd))
172183

184+
initialized = true
173185
endpoint
174186

175187
proc new*(

0 commit comments

Comments
 (0)