1 /* 2 * Copyright (c) 2008-2016 Stefan Krah. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions 6 * are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 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 AND CONTRIBUTORS "AS IS" AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28 29 #include "mpdecimal.h" 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include "typearith.h" 33 #include "mpalloc.h" 34 35 36 #if defined(_MSC_VER) 37 #pragma warning(disable : 4232) 38 #endif 39 40 41 /* Guaranteed minimum allocation for a coefficient. May be changed once 42 at program start using mpd_setminalloc(). */ 43 mpd_ssize_t MPD_MINALLOC = MPD_MINALLOC_MIN; 44 45 /* Custom allocation and free functions */ 46 void *(* mpd_mallocfunc)(size_t size) = malloc; 47 void *(* mpd_reallocfunc)(void *ptr, size_t size) = realloc; 48 void *(* mpd_callocfunc)(size_t nmemb, size_t size) = calloc; 49 void (* mpd_free)(void *ptr) = free; 50 51 52 /* emulate calloc if it is not available */ 53 void * 54 mpd_callocfunc_em(size_t nmemb, size_t size) 55 { 56 void *ptr; 57 size_t req; 58 mpd_size_t overflow; 59 60 #if MPD_SIZE_MAX < SIZE_MAX 61 /* full_coverage test only */ 62 if (nmemb > MPD_SIZE_MAX || size > MPD_SIZE_MAX) { 63 return NULL; 64 } 65 #endif 66 67 req = mul_size_t_overflow((mpd_size_t)nmemb, (mpd_size_t)size, 68 &overflow); 69 if (overflow) { 70 return NULL; 71 } 72 73 ptr = mpd_mallocfunc(req); 74 if (ptr == NULL) { 75 return NULL; 76 } 77 /* used on uint32_t or uint64_t */ 78 memset(ptr, 0, req); 79 80 return ptr; 81 } 82 83 84 /* malloc with overflow checking */ 85 void * 86 mpd_alloc(mpd_size_t nmemb, mpd_size_t size) 87 { 88 mpd_size_t req, overflow; 89 90 req = mul_size_t_overflow(nmemb, size, &overflow); 91 if (overflow) { 92 return NULL; 93 } 94 95 return mpd_mallocfunc(req); 96 } 97 98 /* calloc with overflow checking */ 99 void * 100 mpd_calloc(mpd_size_t nmemb, mpd_size_t size) 101 { 102 mpd_size_t overflow; 103 104 (void)mul_size_t_overflow(nmemb, size, &overflow); 105 if (overflow) { 106 return NULL; 107 } 108 109 return mpd_callocfunc(nmemb, size); 110 } 111 112 /* realloc with overflow checking */ 113 void * 114 mpd_realloc(void *ptr, mpd_size_t nmemb, mpd_size_t size, uint8_t *err) 115 { 116 void *new; 117 mpd_size_t req, overflow; 118 119 req = mul_size_t_overflow(nmemb, size, &overflow); 120 if (overflow) { 121 *err = 1; 122 return ptr; 123 } 124 125 new = mpd_reallocfunc(ptr, req); 126 if (new == NULL) { 127 *err = 1; 128 return ptr; 129 } 130 131 return new; 132 } 133 134 /* struct hack malloc with overflow checking */ 135 void * 136 mpd_sh_alloc(mpd_size_t struct_size, mpd_size_t nmemb, mpd_size_t size) 137 { 138 mpd_size_t req, overflow; 139 140 req = mul_size_t_overflow(nmemb, size, &overflow); 141 if (overflow) { 142 return NULL; 143 } 144 145 req = add_size_t_overflow(req, struct_size, &overflow); 146 if (overflow) { 147 return NULL; 148 } 149 150 return mpd_mallocfunc(req); 151 } 152 153 154 /* Allocate a new decimal with a coefficient of length 'nwords'. In case 155 of an error the return value is NULL. */ 156 mpd_t * 157 mpd_qnew_size(mpd_ssize_t nwords) 158 { 159 mpd_t *result; 160 161 nwords = (nwords < MPD_MINALLOC) ? MPD_MINALLOC : nwords; 162 163 result = mpd_alloc(1, sizeof *result); 164 if (result == NULL) { 165 return NULL; 166 } 167 168 result->data = mpd_alloc(nwords, sizeof *result->data); 169 if (result->data == NULL) { 170 mpd_free(result); 171 return NULL; 172 } 173 174 result->flags = 0; 175 result->exp = 0; 176 result->digits = 0; 177 result->len = 0; 178 result->alloc = nwords; 179 180 return result; 181 } 182 183 /* Allocate a new decimal with a coefficient of length MPD_MINALLOC. 184 In case of an error the return value is NULL. */ 185 mpd_t * 186 mpd_qnew(void) 187 { 188 return mpd_qnew_size(MPD_MINALLOC); 189 } 190 191 /* Allocate new decimal. Caller can check for NULL or MPD_Malloc_error. 192 Raises on error. */ 193 mpd_t * 194 mpd_new(mpd_context_t *ctx) 195 { 196 mpd_t *result; 197 198 result = mpd_qnew(); 199 if (result == NULL) { 200 mpd_addstatus_raise(ctx, MPD_Malloc_error); 201 } 202 return result; 203 } 204 205 /* 206 * Input: 'result' is a static mpd_t with a static coefficient. 207 * Assumption: 'nwords' >= result->alloc. 208 * 209 * Resize the static coefficient to a larger dynamic one and copy the 210 * existing data. If successful, the value of 'result' is unchanged. 211 * Otherwise, set 'result' to NaN and update 'status' with MPD_Malloc_error. 212 */ 213 int 214 mpd_switch_to_dyn(mpd_t *result, mpd_ssize_t nwords, uint32_t *status) 215 { 216 mpd_uint_t *p = result->data; 217 218 assert(nwords >= result->alloc); 219 220 result->data = mpd_alloc(nwords, sizeof *result->data); 221 if (result->data == NULL) { 222 result->data = p; 223 mpd_set_qnan(result); 224 mpd_set_positive(result); 225 result->exp = result->digits = result->len = 0; 226 *status |= MPD_Malloc_error; 227 return 0; 228 } 229 230 memcpy(result->data, p, result->alloc * (sizeof *result->data)); 231 result->alloc = nwords; 232 mpd_set_dynamic_data(result); 233 return 1; 234 } 235 236 /* 237 * Input: 'result' is a static mpd_t with a static coefficient. 238 * 239 * Convert the coefficient to a dynamic one that is initialized to zero. If 240 * malloc fails, set 'result' to NaN and update 'status' with MPD_Malloc_error. 241 */ 242 int 243 mpd_switch_to_dyn_zero(mpd_t *result, mpd_ssize_t nwords, uint32_t *status) 244 { 245 mpd_uint_t *p = result->data; 246 247 result->data = mpd_calloc(nwords, sizeof *result->data); 248 if (result->data == NULL) { 249 result->data = p; 250 mpd_set_qnan(result); 251 mpd_set_positive(result); 252 result->exp = result->digits = result->len = 0; 253 *status |= MPD_Malloc_error; 254 return 0; 255 } 256 257 result->alloc = nwords; 258 mpd_set_dynamic_data(result); 259 260 return 1; 261 } 262 263 /* 264 * Input: 'result' is a static or a dynamic mpd_t with a dynamic coefficient. 265 * Resize the coefficient to length 'nwords': 266 * Case nwords > result->alloc: 267 * If realloc is successful: 268 * 'result' has a larger coefficient but the same value. Return 1. 269 * Otherwise: 270 * Set 'result' to NaN, update status with MPD_Malloc_error and return 0. 271 * Case nwords < result->alloc: 272 * If realloc is successful: 273 * 'result' has a smaller coefficient. result->len is undefined. Return 1. 274 * Otherwise (unlikely): 275 * 'result' is unchanged. Reuse the now oversized coefficient. Return 1. 276 */ 277 int 278 mpd_realloc_dyn(mpd_t *result, mpd_ssize_t nwords, uint32_t *status) 279 { 280 uint8_t err = 0; 281 282 result->data = mpd_realloc(result->data, nwords, sizeof *result->data, &err); 283 if (!err) { 284 result->alloc = nwords; 285 } 286 else if (nwords > result->alloc) { 287 mpd_set_qnan(result); 288 mpd_set_positive(result); 289 result->exp = result->digits = result->len = 0; 290 *status |= MPD_Malloc_error; 291 return 0; 292 } 293 294 return 1; 295 } 296 297 298