Line data Source code
1 : /*
2 : * Copyright (c) 2008-2012 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 "memory.h"
34 :
35 :
36 : /* Guaranteed minimum allocation for a coefficient. May be changed once
37 : at program start using mpd_setminalloc(). */
38 : mpd_ssize_t MPD_MINALLOC = MPD_MINALLOC_MIN;
39 :
40 : /* Custom allocation and free functions */
41 : void *(* mpd_mallocfunc)(size_t size) = malloc;
42 : void *(* mpd_reallocfunc)(void *ptr, size_t size) = realloc;
43 : void *(* mpd_callocfunc)(size_t nmemb, size_t size) = calloc;
44 : void (* mpd_free)(void *ptr) = free;
45 :
46 :
47 : /* emulate calloc if it is not available */
48 : void *
49 0 : mpd_callocfunc_em(size_t nmemb, size_t size)
50 : {
51 : void *ptr;
52 : size_t req;
53 : mpd_size_t overflow;
54 :
55 : #if MPD_SIZE_MAX < SIZE_MAX
56 : /* full_coverage test only */
57 : if (nmemb > MPD_SIZE_MAX || size > MPD_SIZE_MAX) {
58 : return NULL;
59 : }
60 : #endif
61 :
62 0 : req = mul_size_t_overflow((mpd_size_t)nmemb, (mpd_size_t)size,
63 : &overflow);
64 0 : if (overflow) {
65 0 : return NULL;
66 : }
67 :
68 0 : ptr = mpd_mallocfunc(req);
69 0 : if (ptr == NULL) {
70 0 : return NULL;
71 : }
72 : /* used on uint32_t or uint64_t */
73 0 : memset(ptr, 0, req);
74 :
75 0 : return ptr;
76 : }
77 :
78 :
79 : /* malloc with overflow checking */
80 : void *
81 0 : mpd_alloc(mpd_size_t nmemb, mpd_size_t size)
82 : {
83 : mpd_size_t req, overflow;
84 :
85 0 : req = mul_size_t_overflow(nmemb, size, &overflow);
86 0 : if (overflow) {
87 0 : return NULL;
88 : }
89 :
90 0 : return mpd_mallocfunc(req);
91 : }
92 :
93 : /* calloc with overflow checking */
94 : void *
95 0 : mpd_calloc(mpd_size_t nmemb, mpd_size_t size)
96 : {
97 : mpd_size_t overflow;
98 :
99 0 : (void)mul_size_t_overflow(nmemb, size, &overflow);
100 0 : if (overflow) {
101 0 : return NULL;
102 : }
103 :
104 0 : return mpd_callocfunc(nmemb, size);
105 : }
106 :
107 : /* realloc with overflow checking */
108 : void *
109 0 : mpd_realloc(void *ptr, mpd_size_t nmemb, mpd_size_t size, uint8_t *err)
110 : {
111 : void *new;
112 : mpd_size_t req, overflow;
113 :
114 0 : req = mul_size_t_overflow(nmemb, size, &overflow);
115 0 : if (overflow) {
116 0 : *err = 1;
117 0 : return ptr;
118 : }
119 :
120 0 : new = mpd_reallocfunc(ptr, req);
121 0 : if (new == NULL) {
122 0 : *err = 1;
123 0 : return ptr;
124 : }
125 :
126 0 : return new;
127 : }
128 :
129 : /* struct hack malloc with overflow checking */
130 : void *
131 0 : mpd_sh_alloc(mpd_size_t struct_size, mpd_size_t nmemb, mpd_size_t size)
132 : {
133 : mpd_size_t req, overflow;
134 :
135 0 : req = mul_size_t_overflow(nmemb, size, &overflow);
136 0 : if (overflow) {
137 0 : return NULL;
138 : }
139 :
140 0 : req = add_size_t_overflow(req, struct_size, &overflow);
141 0 : if (overflow) {
142 0 : return NULL;
143 : }
144 :
145 0 : return mpd_mallocfunc(req);
146 : }
147 :
148 :
149 : /* Allocate a new decimal with a coefficient of length 'nwords'. In case
150 : of an error the return value is NULL. */
151 : mpd_t *
152 0 : mpd_qnew_size(mpd_ssize_t nwords)
153 : {
154 : mpd_t *result;
155 :
156 0 : nwords = (nwords < MPD_MINALLOC) ? MPD_MINALLOC : nwords;
157 :
158 0 : result = mpd_alloc(1, sizeof *result);
159 0 : if (result == NULL) {
160 0 : return NULL;
161 : }
162 :
163 0 : result->data = mpd_alloc(nwords, sizeof *result->data);
164 0 : if (result->data == NULL) {
165 0 : mpd_free(result);
166 0 : return NULL;
167 : }
168 :
169 0 : result->flags = 0;
170 0 : result->exp = 0;
171 0 : result->digits = 0;
172 0 : result->len = 0;
173 0 : result->alloc = nwords;
174 :
175 0 : return result;
176 : }
177 :
178 : /* Allocate a new decimal with a coefficient of length MPD_MINALLOC.
179 : In case of an error the return value is NULL. */
180 : mpd_t *
181 0 : mpd_qnew(void)
182 : {
183 0 : return mpd_qnew_size(MPD_MINALLOC);
184 : }
185 :
186 : /* Allocate new decimal. Caller can check for NULL or MPD_Malloc_error.
187 : Raises on error. */
188 : mpd_t *
189 0 : mpd_new(mpd_context_t *ctx)
190 : {
191 : mpd_t *result;
192 :
193 0 : result = mpd_qnew();
194 0 : if (result == NULL) {
195 0 : mpd_addstatus_raise(ctx, MPD_Malloc_error);
196 : }
197 0 : return result;
198 : }
199 :
200 : /*
201 : * Input: 'result' is a static mpd_t with a static coefficient.
202 : * Assumption: 'nwords' >= result->alloc.
203 : *
204 : * Resize the static coefficient to a larger dynamic one and copy the
205 : * existing data. If successful, the value of 'result' is unchanged.
206 : * Otherwise, set 'result' to NaN and update 'status' with MPD_Malloc_error.
207 : */
208 : int
209 0 : mpd_switch_to_dyn(mpd_t *result, mpd_ssize_t nwords, uint32_t *status)
210 : {
211 0 : mpd_uint_t *p = result->data;
212 :
213 : assert(nwords >= result->alloc);
214 :
215 0 : result->data = mpd_alloc(nwords, sizeof *result->data);
216 0 : if (result->data == NULL) {
217 0 : result->data = p;
218 0 : mpd_set_qnan(result);
219 0 : mpd_set_positive(result);
220 0 : result->exp = result->digits = result->len = 0;
221 0 : *status |= MPD_Malloc_error;
222 0 : return 0;
223 : }
224 :
225 0 : memcpy(result->data, p, result->alloc * (sizeof *result->data));
226 0 : result->alloc = nwords;
227 0 : mpd_set_dynamic_data(result);
228 0 : return 1;
229 : }
230 :
231 : /*
232 : * Input: 'result' is a static mpd_t with a static coefficient.
233 : *
234 : * Convert the coefficient to a dynamic one that is initialized to zero. If
235 : * malloc fails, set 'result' to NaN and update 'status' with MPD_Malloc_error.
236 : */
237 : int
238 0 : mpd_switch_to_dyn_zero(mpd_t *result, mpd_ssize_t nwords, uint32_t *status)
239 : {
240 0 : mpd_uint_t *p = result->data;
241 :
242 0 : result->data = mpd_calloc(nwords, sizeof *result->data);
243 0 : if (result->data == NULL) {
244 0 : result->data = p;
245 0 : mpd_set_qnan(result);
246 0 : mpd_set_positive(result);
247 0 : result->exp = result->digits = result->len = 0;
248 0 : *status |= MPD_Malloc_error;
249 0 : return 0;
250 : }
251 :
252 0 : result->alloc = nwords;
253 0 : mpd_set_dynamic_data(result);
254 :
255 0 : return 1;
256 : }
257 :
258 : /*
259 : * Input: 'result' is a static or a dynamic mpd_t with a dynamic coefficient.
260 : * Resize the coefficient to length 'nwords':
261 : * Case nwords > result->alloc:
262 : * If realloc is successful:
263 : * 'result' has a larger coefficient but the same value. Return 1.
264 : * Otherwise:
265 : * Set 'result' to NaN, update status with MPD_Malloc_error and return 0.
266 : * Case nwords < result->alloc:
267 : * If realloc is successful:
268 : * 'result' has a smaller coefficient. result->len is undefined. Return 1.
269 : * Otherwise (unlikely):
270 : * 'result' is unchanged. Reuse the now oversized coefficient. Return 1.
271 : */
272 : int
273 0 : mpd_realloc_dyn(mpd_t *result, mpd_ssize_t nwords, uint32_t *status)
274 : {
275 0 : uint8_t err = 0;
276 :
277 0 : result->data = mpd_realloc(result->data, nwords, sizeof *result->data, &err);
278 0 : if (!err) {
279 0 : result->alloc = nwords;
280 : }
281 0 : else if (nwords > result->alloc) {
282 0 : mpd_set_qnan(result);
283 0 : mpd_set_positive(result);
284 0 : result->exp = result->digits = result->len = 0;
285 0 : *status |= MPD_Malloc_error;
286 0 : return 0;
287 : }
288 :
289 0 : return 1;
290 : }
291 :
292 :
|