From 9c6c6f495b8469ca5e105f5ddb02a69d1303a106 Mon Sep 17 00:00:00 2001 From: Chong Yidong Date: Thu, 27 Oct 2011 14:07:09 +0800 Subject: [PATCH] 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. --- src/ChangeLog | 9 ++++++ src/gnutls.c | 89 +++++++++++++++++++++++++-------------------------- src/gnutls.h | 1 + src/process.c | 7 ++++ 4 files changed, 61 insertions(+), 45 deletions(-) diff --git a/src/ChangeLog b/src/ChangeLog index 3caecf32049..65995d0ac92 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,12 @@ +2011-10-27 Chong Yidong + + * 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 * image.c (x_create_x_image_and_pixmap): diff --git a/src/gnutls.c b/src/gnutls.c index 0743ef3f4ee..f836692198c 100644 --- a/src/gnutls.c +++ b/src/gnutls.c @@ -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"); diff --git a/src/gnutls.h b/src/gnutls.h index e2a9bc9eaea..5ec6fb76c01 100644 --- a/src/gnutls.h +++ b/src/gnutls.h @@ -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); diff --git a/src/process.c b/src/process.c index 90ad9c21681..3daa55b259e 100644 --- a/src/process.c +++ b/src/process.c @@ -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; -- 2.39.5