]> git.llucax.com Git - software/mutt-debian.git/blob - safe_asprintf.c
584138-mx_update_context-segfault.patch: fix a segfault due to holes in IMAP headers...
[software/mutt-debian.git] / safe_asprintf.c
1 /*
2  * Copyright (C) 2010 Michael R. Elkins <me@mutt.org>
3  * 
4  *     This program is free software; you can redistribute it and/or modify
5  *     it under the terms of the GNU General Public License as published by
6  *     the Free Software Foundation; either version 2 of the License, or
7  *     (at your option) any later version.
8  * 
9  *     This program is distributed in the hope that it will be useful,
10  *     but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *     GNU General Public License for more details.
13  * 
14  *     You should have received a copy of the GNU General Public License
15  *     along with this program; if not, write to the Free Software
16  *     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17  */ 
18
19 #include <stdio.h>
20 #include "lib.h"
21
22 /* NOTE: Currently there is no check in configure.ac for vasprintf(3).  the
23  * undefined behavior of the error condition makes it difficult to write a safe
24  * version using it.
25  */
26
27 #ifdef HAVE_VASPRINTF
28 int safe_asprintf (char **strp, const char *fmt, ...)
29 {
30   va_list ap;
31   int n;
32
33   va_start (ap, fmt);
34   n = vasprintf (strp, fmt, ap);
35   va_end (ap);
36
37   /* GNU libc man page for vasprintf(3) states that the value of *strp
38    * is undefined when the return code is -1.
39    */
40   if (n < 0)
41   {
42     mutt_error _("Out of memory!");
43     sleep (1);
44     mutt_exit (1);
45   }
46
47   if (n == 0)
48   {
49     /* Mutt convention is to use NULL for 0-length strings */
50     FREE (strp); /* __FREE_CHECKED__ */
51   }
52
53   return n;
54 }
55 #else
56 /* Allocate a C-string large enough to contain the formatted string.
57  * This is essentially malloc+sprintf in one.
58  */
59 int safe_asprintf (char **strp, const char *fmt, ...)
60 {
61   int rlen = STRING;
62   int n;
63
64   *strp = safe_malloc (rlen);
65   for (;;)
66   {
67     va_list ap;
68     va_start (ap, fmt);
69     n = vsnprintf (*strp, rlen, fmt, ap);
70     va_end (ap);
71     if (n < 0)
72     {
73       FREE (strp); /* __FREE_CHECKED__ */
74       return n;
75     }
76
77     if (n < rlen)
78     {
79       /* reduce space to just that which was used.  note that 'n' does not
80        * include the terminal nul char.
81        */
82       if (n == 0) /* convention is to use NULL for zero-length strings. */
83         FREE (strp); /* __FREE_CHECKED__ */
84       else if (n != rlen - 1)
85         safe_realloc (strp, n + 1);
86       return n;
87     }
88     /* increase size and try again */
89     rlen = n + 1;
90     safe_realloc (strp, rlen);
91   }
92   /* not reached */
93 }
94 #endif /* HAVE_ASPRINTF */
95