chan_sip: Fix theoretical leak of p->refer.
authorCorey Farrell <git@cfware.com>
Mon, 17 Nov 2014 16:02:06 +0000 (16:02 +0000)
committerCorey Farrell <git@cfware.com>
Mon, 17 Nov 2014 16:02:06 +0000 (16:02 +0000)
If transmit_refer is called when p->refer is already allocated,
it leaks the previous allocation.  Updated code to always free
previous allocation during a new allocation.  Also instead of
checking if we have a previous allocation, always create a
clean record.

ASTERISK-15242 #close
Reported by: David Woolley
Review: https://reviewboard.asterisk.org/r/4160/
........

Merged revisions 428117 from http://svn.asterisk.org/svn/asterisk/branches/11
........

Merged revisions 428118 from http://svn.asterisk.org/svn/asterisk/branches/12
........

Merged revisions 428119 from http://svn.asterisk.org/svn/asterisk/branches/13

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@428120 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_sip.c

index 1cf83e4..ef074a3 100644 (file)
@@ -1258,6 +1258,7 @@ static int dialog_find_multiple(void *obj, void *arg, int flags);
 static struct ast_channel *sip_pvt_lock_full(struct sip_pvt *pvt);
 /* static int sip_addrcmp(char *name, struct sockaddr_in *sin);        Support for peer matching */
 static int sip_refer_alloc(struct sip_pvt *p);
+static void sip_refer_destroy(struct sip_pvt *p);
 static int sip_notify_alloc(struct sip_pvt *p);
 static int do_magic_pickup(struct ast_channel *channel, const char *extension, const char *context);
 static void set_peer_nat(const struct sip_pvt *p, struct sip_peer *peer);
@@ -6485,11 +6486,7 @@ void __sip_destroy(struct sip_pvt *p, int lockowner, int lockdialoglist)
                ast_udptl_destroy(p->udptl);
                p->udptl = NULL;
        }
-       if (p->refer) {
-               ast_string_field_free_memory(p->refer);
-               ast_free(p->refer);
-               p->refer = NULL;
-       }
+       sip_refer_destroy(p);
        sip_route_clear(&p->route);
        deinit_req(&p->initreq);
 
@@ -15564,10 +15561,21 @@ static int transmit_message(struct sip_pvt *p, int init, int auth)
 /*! \brief Allocate SIP refer structure */
 static int sip_refer_alloc(struct sip_pvt *p)
 {
+       sip_refer_destroy(p);
        p->refer = ast_calloc_with_stringfields(1, struct sip_refer, 512);
        return p->refer ? 1 : 0;
 }
 
+/*! \brief Destroy SIP refer structure */
+static void sip_refer_destroy(struct sip_pvt *p)
+{
+       if (p->refer) {
+               ast_string_field_free_memory(p->refer);
+               ast_free(p->refer);
+               p->refer = NULL;
+       }
+}
+
 /*! \brief Allocate SIP refer structure */
 static int sip_notify_alloc(struct sip_pvt *p)
 {
@@ -18123,8 +18131,9 @@ static int get_also_info(struct sip_pvt *p, struct sip_request *oreq)
        struct sip_refer *refer = NULL;
        const char *transfer_context = NULL;
 
-       if (!p->refer && !sip_refer_alloc(p))
+       if (!sip_refer_alloc(p)) {
                return -1;
+       }
 
        refer = p->refer;
 
@@ -25246,7 +25255,7 @@ static int handle_request_invite(struct sip_pvt *p, struct sip_request *req, str
                replace_id = ast_strdupa(p_replaces);
                ast_uri_decode(replace_id, ast_uri_sip_user);
 
-               if (!p->refer && !sip_refer_alloc(p)) {
+               if (!sip_refer_alloc(p)) {
                        transmit_response_reliable(p, "500 Server Internal Error", req);
                        append_history(p, "Xfer", "INVITE/Replace Failed. Out of memory.");
                        sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT);
@@ -26105,7 +26114,7 @@ static int handle_request_refer(struct sip_pvt *p, struct sip_request *req, uint
        }
 
        /* Allocate memory for call transfer data */
-       if (!p->refer && !sip_refer_alloc(p)) {
+       if (!sip_refer_alloc(p)) {
                transmit_response(p, "500 Internal Server Error", req);
                append_history(p, "Xfer", "Refer failed. Memory allocation error.");
                return -3;