/* * Copyright (C) 2010 Michael R. Elkins * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include "lib.h" /* NOTE: Currently there is no check in configure.ac for vasprintf(3). the * undefined behavior of the error condition makes it difficult to write a safe * version using it. */ #ifdef HAVE_VASPRINTF int safe_asprintf (char **strp, const char *fmt, ...) { va_list ap; int n; va_start (ap, fmt); n = vasprintf (strp, fmt, ap); va_end (ap); /* GNU libc man page for vasprintf(3) states that the value of *strp * is undefined when the return code is -1. */ if (n < 0) { mutt_error _("Out of memory!"); sleep (1); mutt_exit (1); } if (n == 0) { /* Mutt convention is to use NULL for 0-length strings */ FREE (strp); /* __FREE_CHECKED__ */ } return n; } #else /* Allocate a C-string large enough to contain the formatted string. * This is essentially malloc+sprintf in one. */ int safe_asprintf (char **strp, const char *fmt, ...) { int rlen = STRING; int n; *strp = safe_malloc (rlen); for (;;) { va_list ap; va_start (ap, fmt); n = vsnprintf (*strp, rlen, fmt, ap); va_end (ap); if (n < 0) { FREE (strp); /* __FREE_CHECKED__ */ return n; } if (n < rlen) { /* reduce space to just that which was used. note that 'n' does not * include the terminal nul char. */ if (n == 0) /* convention is to use NULL for zero-length strings. */ FREE (strp); /* __FREE_CHECKED__ */ else if (n != rlen - 1) safe_realloc (strp, n + 1); return n; } /* increase size and try again */ rlen = n + 1; safe_realloc (strp, rlen); } /* not reached */ } #endif /* HAVE_ASPRINTF */