1 /* 2 * Revision 12: http://theos.com/~deraadt/snprintf.c 3 * 4 * Copyright (c) 1997 Theo de Raadt 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #ifndef __VMS 28 # include <sys/param.h> 29 #endif 30 #include <sys/types.h> 31 #include <sys/mman.h> 32 #include <signal.h> 33 #include <stdio.h> 34 #if __STDC__ 35 #include <stdarg.h> 36 #include <stdlib.h> 37 #else 38 #include <varargs.h> 39 #endif 40 #include <setjmp.h> 41 #include <unistd.h> 42 #include <string.h> 43 44 #ifndef roundup 45 #define roundup(x, y) ((((x)+((y)-1))/(y))*(y)) 46 #endif 47 48 #ifdef __sgi 49 #define size_t ssize_t 50 #endif 51 52 static int pgsize; 53 static char *curobj; 54 static int caught; 55 static sigjmp_buf bail; 56 57 #define EXTRABYTES 2 /* XXX: why 2? you don't want to know */ 58 59 static char * 60 msetup(str, n) 61 char *str; 62 size_t n; 63 { 64 char *e; 65 66 if (n == 0) 67 return NULL; 68 if (pgsize == 0) 69 pgsize = getpagesize(); 70 curobj = (char *)malloc(n + EXTRABYTES + pgsize * 2); 71 if (curobj == NULL) 72 return NULL; 73 e = curobj + n + EXTRABYTES; 74 e = (char *)roundup((unsigned long)e, pgsize); 75 if (mprotect(e, pgsize, PROT_NONE) == -1) { 76 free(curobj); 77 curobj = NULL; 78 return NULL; 79 } 80 e = e - n - EXTRABYTES; 81 *e = '\0'; 82 return (e); 83 } 84 85 static void 86 mcatch( int a ) 87 { 88 siglongjmp(bail, 1); 89 } 90 91 static void 92 mcleanup(str, n, p) 93 char *str; 94 size_t n; 95 char *p; 96 { 97 strncpy(str, p, n-1); 98 str[n-1] = '\0'; 99 if (mprotect((caddr_t)(p + n + EXTRABYTES), pgsize, 100 PROT_READ|PROT_WRITE|PROT_EXEC) == -1) 101 mprotect((caddr_t)(p + n + EXTRABYTES), pgsize, 102 PROT_READ|PROT_WRITE); 103 free(curobj); 104 } 105 106 int 107 #if __STDC__ 108 vsnprintf(char *str, size_t n, char const *fmt, va_list ap) 109 #else 110 vsnprintf(str, n, fmt, ap) 111 char *str; 112 size_t n; 113 char *fmt; 114 char *ap; 115 #endif 116 { 117 struct sigaction osa, nsa; 118 char *p; 119 int ret = n + 1; /* if we bail, indicated we overflowed */ 120 121 memset(&nsa, 0, sizeof nsa); 122 nsa.sa_handler = mcatch; 123 sigemptyset(&nsa.sa_mask); 124 125 p = msetup(str, n); 126 if (p == NULL) { 127 *str = '\0'; 128 return 0; 129 } 130 if (sigsetjmp(bail, 1) == 0) { 131 if (sigaction(SIGSEGV, &nsa, &osa) == -1) { 132 mcleanup(str, n, p); 133 return (0); 134 } 135 ret = vsprintf(p, fmt, ap); 136 } 137 mcleanup(str, n, p); 138 (void) sigaction(SIGSEGV, &osa, NULL); 139 return (ret); 140 } 141 142 int 143 #if __STDC__ 144 snprintf(char *str, size_t n, char const *fmt, ...) 145 #else 146 snprintf(str, n, fmt, va_alist) 147 char *str; 148 size_t n; 149 char *fmt; 150 va_dcl 151 #endif 152 { 153 va_list ap; 154 #if __STDC__ 155 va_start(ap, fmt); 156 #else 157 va_start(ap); 158 #endif 159 160 return (vsnprintf(str, n, fmt, ap)); 161 va_end(ap); 162 } 163 164 165 166