Commit 9c6c6f49 authored by Chong Yidong's avatar Chong Yidong

Fix a memory leak in the built-in GnuTLS support.

* src/gnutls.c (emacs_gnutls_deinit): New function.  Deallocate
credentials structures as well as calling gnutls_deinit.
(Fgnutls_deinit, Fgnutls_boot): Use it.

* src/process.c (make_process): Initialize GnuTLS credentials to NULL.
(deactivate_process): Call emacs_gnutls_deinit.
parent 15de15c6
2011-10-27 Chong Yidong <cyd@gnu.org>
* gnutls.c (emacs_gnutls_deinit): New function. Deallocate
credentials structures as well as calling gnutls_deinit.
(Fgnutls_deinit, Fgnutls_boot): Use it.
* process.c (make_process): Initialize GnuTLS credentials to NULL.
(deactivate_process): Call emacs_gnutls_deinit.
2011-10-27 Juanma Barranquero <lekktu@gmail.com>
* image.c (x_create_x_image_and_pixmap):
......
......@@ -464,6 +464,42 @@ gnutls_make_error (int err)
return make_number (err);
}
Lisp_Object
emacs_gnutls_deinit (Lisp_Object proc)
{
int log_level;
CHECK_PROCESS (proc);
if (XPROCESS (proc)->gnutls_p == 0)
return Qnil;
log_level = XPROCESS (proc)->gnutls_log_level;
if (XPROCESS (proc)->gnutls_x509_cred)
{
GNUTLS_LOG (2, log_level, "Deallocating x509 credentials");
fn_gnutls_certificate_free_credentials (XPROCESS (proc)->gnutls_x509_cred);
XPROCESS (proc)->gnutls_x509_cred = NULL;
}
if (XPROCESS (proc)->gnutls_anon_cred)
{
GNUTLS_LOG (2, log_level, "Deallocating anon credentials");
fn_gnutls_anon_free_client_credentials (XPROCESS (proc)->gnutls_anon_cred);
XPROCESS (proc)->gnutls_anon_cred = NULL;
}
if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_INIT)
{
fn_gnutls_deinit (XPROCESS (proc)->gnutls_state);
GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT - 1;
}
XPROCESS (proc)->gnutls_p = 0;
return Qt;
}
DEFUN ("gnutls-get-initstage", Fgnutls_get_initstage, Sgnutls_get_initstage, 1, 1, 0,
doc: /* Return the GnuTLS init stage of process PROC.
See also `gnutls-boot'. */)
......@@ -551,18 +587,7 @@ DEFUN ("gnutls-deinit", Fgnutls_deinit, Sgnutls_deinit, 1, 1, 0,
See also `gnutls-init'. */)
(Lisp_Object proc)
{
gnutls_session_t state;
CHECK_PROCESS (proc);
state = XPROCESS (proc)->gnutls_state;
if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_INIT)
{
fn_gnutls_deinit (state);
GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_INIT - 1;
}
return Qt;
return emacs_gnutls_deinit (proc);
}
DEFUN ("gnutls-available-p", Fgnutls_available_p, Sgnutls_available_p, 0, 0, 0,
......@@ -733,9 +758,6 @@ one trustfile (usually a CA bundle). */)
c_hostname = SSDATA (hostname);
state = XPROCESS (proc)->gnutls_state;
XPROCESS (proc)->gnutls_p = 1;
if (NUMBERP (loglevel))
{
fn_gnutls_global_set_log_function (gnutls_log_function);
......@@ -749,40 +771,17 @@ one trustfile (usually a CA bundle). */)
if (! NILP (Fgnutls_errorp (global_init)))
return global_init;
/* deinit and free resources. */
if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_CRED_ALLOC)
{
GNUTLS_LOG (1, max_log_level, "deallocating credentials");
if (EQ (type, Qgnutls_x509pki))
{
GNUTLS_LOG (2, max_log_level, "deallocating x509 credentials");
x509_cred = XPROCESS (proc)->gnutls_x509_cred;
fn_gnutls_certificate_free_credentials (x509_cred);
}
else if (EQ (type, Qgnutls_anon))
{
GNUTLS_LOG (2, max_log_level, "deallocating anon credentials");
anon_cred = XPROCESS (proc)->gnutls_anon_cred;
fn_gnutls_anon_free_client_credentials (anon_cred);
}
else
{
error ("unknown credential type");
ret = GNUTLS_EMACS_ERROR_INVALID_TYPE;
}
if (GNUTLS_INITSTAGE (proc) >= GNUTLS_STAGE_INIT)
{
GNUTLS_LOG (1, max_log_level, "deallocating x509 credentials");
Fgnutls_deinit (proc);
}
}
/* Before allocating new credentials, deallocate any credentials
that PROC might already have. */
emacs_gnutls_deinit (proc);
/* Mark PROC as a GnuTLS process. */
XPROCESS (proc)->gnutls_p = 1;
XPROCESS (proc)->gnutls_x509_cred = NULL;
XPROCESS (proc)->gnutls_anon_cred = NULL;
GNUTLS_INITSTAGE (proc) = GNUTLS_STAGE_EMPTY;
GNUTLS_LOG (1, max_log_level, "allocating credentials");
if (EQ (type, Qgnutls_x509pki))
{
GNUTLS_LOG (2, max_log_level, "allocating x509 credentials");
......
......@@ -60,6 +60,7 @@ emacs_gnutls_read (struct Lisp_Process *proc, char *buf, EMACS_INT nbyte);
extern int emacs_gnutls_record_check_pending (gnutls_session_t state);
extern void emacs_gnutls_transport_set_errno (gnutls_session_t state, int err);
extern Lisp_Object emacs_gnutls_deinit (Lisp_Object);
extern void syms_of_gnutls (void);
......
......@@ -642,6 +642,8 @@ make_process (Lisp_Object name)
p->gnutls_initstage = GNUTLS_STAGE_EMPTY;
p->gnutls_log_level = 0;
p->gnutls_p = 0;
p->gnutls_x509_cred = NULL;
p->gnutls_anon_cred = NULL;
#endif
/* If name is already in use, modify it until it is unused. */
......@@ -3867,6 +3869,11 @@ deactivate_process (Lisp_Object proc)
register int inchannel, outchannel;
register struct Lisp_Process *p = XPROCESS (proc);
#ifdef HAVE_GNUTLS
/* Delete GnuTLS structures in PROC, if any. */
emacs_gnutls_deinit (proc);
#endif /* HAVE_GNUTLS */
inchannel = p->infd;
outchannel = p->outfd;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment