math/gfreduce.[ch]: Fix out-of-bounds memory access.
[u/mdw/catacomb] / math / mp-mem.c
1 /* -*-c-*-
2 *
3 * Memory management for multiprecision numbers
4 *
5 * (c) 1999 Straylight/Edgeware
6 */
7
8 /*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of Catacomb.
11 *
12 * Catacomb is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU Library General Public License as
14 * published by the Free Software Foundation; either version 2 of the
15 * License, or (at your option) any later version.
16 *
17 * Catacomb is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU Library General Public License for more details.
21 *
22 * You should have received a copy of the GNU Library General Public
23 * License along with Catacomb; if not, write to the Free
24 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
25 * MA 02111-1307, USA.
26 */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include <mLib/sub.h>
31
32
33 #include "mp.h"
34
35 /*----- Main code ---------------------------------------------------------*/
36
37 /* --- @mp_new@ --- *
38 *
39 * Arguments: @size_t sz@ = size of vector required
40 * @unsigned f@ = flags to set
41 *
42 * Returns: Pointer to a new MP structure.
43 *
44 * Use: Allocates a new multiprecision integer. The data space is
45 * allocated from either the standard global or secret arena,
46 * depending on the initial flags requested.
47 */
48
49 mp *mp_new(size_t sz, unsigned f)
50 {
51 mp *m = CREATE(mp);
52 m->a = (f & MP_BURN) ? MPARENA_SECURE : MPARENA_GLOBAL;
53 m->v = mpalloc(m->a, sz);
54 m->vl = m->v + sz;
55 m->sz = sz;
56 m->f = f & ~(MP_CONST | MP_DESTROYED);
57 m->ref = 1;
58 return (m);
59 }
60
61 /* --- @mp_create@ --- *
62 *
63 * Arguments: @size_t sz@ = size of vector required
64 *
65 * Returns: Pointer to pristine new MP structure with enough memory
66 * bolted onto it.
67 *
68 * Use: Creates a new multiprecision integer, initially zero. The
69 * integer has a single reference.
70 */
71
72 mp *mp_create(size_t sz)
73 {
74 mp *m = CREATE(mp);
75 m->v = mpalloc(MPARENA_GLOBAL, sz);
76 m->vl = m->v + sz;
77 m->sz = sz;
78 m->a = MPARENA_GLOBAL;
79 m->f = MP_UNDEF;
80 m->ref = 1;
81 return (m);
82 }
83
84 /* --- @mp_createsecure@ --- *
85 *
86 * Arguments: @size_t sz@ = size of vector required
87 *
88 * Returns: Pointer to pristine new MP structure with enough memory
89 * bolted onto it.
90 *
91 * Use: Creates a new multiprecision integer with indeterminate
92 * contents. The integer has a single reference. The integer's
93 * data space is allocated from the secure arena. Its burn flag
94 * is set.
95 */
96
97 mp *mp_createsecure(size_t sz)
98 {
99 mp *m = CREATE(mp);
100 m->v = mpalloc(MPARENA_SECURE, sz);
101 m->vl = m->v + sz;
102 m->sz = sz;
103 m->a = MPARENA_SECURE;
104 m->f = MP_UNDEF | MP_BURN;
105 m->ref = 1;
106 return (m);
107 }
108
109 /* --- @mp_build@ --- *
110 *
111 * Arguments: @mp *m@ = pointer to an MP block to fill in
112 * @mpw *v@ = pointer to a word array
113 * @mpw *vl@ = pointer just past end of array
114 *
115 * Returns: ---
116 *
117 * Use: Creates a multiprecision integer representing some smallish
118 * number. You must provide storage for the number and dispose
119 * of it when you've finished with it. The number is marked as
120 * constant while it exists.
121 */
122
123 void mp_build(mp *m, mpw *v, mpw *vl)
124 {
125 m->v = v;
126 m->vl = vl;
127 m->sz = vl - v;
128 m->a = MPARENA_GLOBAL;
129 m->f = MP_CONST;
130 m->ref = 1;
131 }
132
133 /* --- @mp_destroy@ --- *
134 *
135 * Arguments: @mp *m@ = pointer to a multiprecision integer
136 *
137 * Returns: ---
138 *
139 * Use: Destroys a multiprecision integer. The reference count isn't
140 * checked. Don't use this function if you don't know what
141 * you're doing: use @mp_drop@ instead.
142 */
143
144 void mp_destroy(mp *m)
145 {
146 assert(((void)"Destroying a free integer", !(m->f & MP_DESTROYED)));
147 assert(((void)"Attempted to destroy a constant", !(m->f & MP_CONST)));
148 if (m->f & MP_BURN)
149 memset(m->v, 0, MPWS(m->sz));
150 mpfree(m->a, m->v);
151 m->f |= MP_DESTROYED;
152 DESTROY(m);
153 }
154
155 /* --- @mp_copy@ --- *
156 *
157 * Arguments: @mp *m@ = pointer to a multiprecision integer
158 *
159 * Returns: A copy of the given multiprecision integer.
160 *
161 * Use: Copies the given integer. In fact you just get another
162 * reference to the same old one again.
163 */
164
165 mp *mp_copy(mp *m) { return MP_COPY(m); }
166
167 /* --- @mp_drop@ --- *
168 *
169 * Arguments: @mp *m@ = pointer to a multiprecision integer
170 *
171 * Returns: ---
172 *
173 * Use: Drops a reference to an integer which isn't wanted any more.
174 * If there are no more references, the integer is destroyed.
175 */
176
177 void mp_drop(mp *m) { if (m) MP_DROP(m); }
178
179 /* --- @mp_split@ --- *
180 *
181 * Arguments: @mp *m@ = pointer to a multiprecision integer
182 *
183 * Returns: A reference to the same integer, possibly with a different
184 * address.
185 *
186 * Use: Splits off a modifiable version of the integer referred to.
187 */
188
189 mp *mp_split(mp *m) { MP_SPLIT(m); return (m); }
190
191 /* --- @mp_resize@ --- *
192 *
193 * Arguments: @mp *m@ = pointer to a multiprecision integer
194 * @size_t sz@ = new size
195 *
196 * Returns: ---
197 *
198 * Use: Changes an integer's size. The length and value are not
199 * changed. It is an error to
200 */
201
202 void mp_resize(mp *m, size_t sz) { MP_RESIZE(m, sz); }
203
204 /* --- @mp_ensure@ --- *
205 *
206 * Arguments: @mp *m@ = pointer to a multiprecision integer
207 * @size_t sz@ = required length
208 *
209 * Returns: ---
210 *
211 * Use: Changes an integer's length. If there is not enough space
212 * allocated for the new length then the size is increased. It
213 */
214
215 void mp_ensure(mp *m, size_t sz) { MP_ENSURE(m, sz); }
216
217 /* --- @mp_dest@ --- *
218 *
219 * Arguments: @mp *m@ = a suggested destination integer
220 * @size_t sz@ = size required for result, in digits
221 * @unsigned f@ = various flags
222 *
223 * Returns: A pointer to an appropriate destination.
224 *
225 * Use: Converts a suggested destination into a real destination with
226 * the required properties. If the real destination is @d@,
227 * then the following properties will hold:
228 *
229 * * @d@ will have exactly one reference.
230 *
231 * * If @m@ is not @MP_NEW@, then the contents of @m@ will not
232 * change, unless @f@ has the @MP_UNDEF@ flag set.
233 *
234 * * If @m@ is not @MP_NEW@, then he reference count of @m@ on
235 * entry is equal to the sum of the counts of @d@ and @m@ on
236 * exit.
237 *
238 * * The size of @d@ will be at least @sz@.
239 *
240 * * If @f@ has the @MP_BURN@ flag set, then @d@ will be
241 * allocated from @MPARENA_SECURE@.
242 *
243 * Understanding this function is crucial to using Catacomb's
244 * multiprecision integer library effectively.
245 */
246
247 mp *mp_dest(mp *m, size_t sz, unsigned f)
248 {
249 /* --- If no destination, make one --- */
250
251 if (m == MP_NEWSEC)
252 m = mp_new(sz, f | MP_UNDEF | MP_BURN);
253 else if (m == MP_NEW)
254 m = mp_new(sz, f | MP_UNDEF);
255 else {
256 size_t len = MP_LEN(m);
257 unsigned undef = (m->f | f) & MP_UNDEF;
258
259 /* --- If the value must be preserved, the block can't shrink --- */
260
261 if (!undef && sz < len)
262 sz = len;
263
264 /* --- Otherwise check whether the destination is suitable --- */
265
266 if (m->ref > 1 || (m->f & MP_CONST) ||
267 sz > m->sz || ((f & ~m->f) & MP_BURN)) {
268
269 /* --- No -- allocate a new buffer --- *
270 *
271 * The buffer must be secure if (a) the caller requested a secure
272 * buffer, or (b) the old buffer is secure and I'm not allowed to
273 * discard the old contents.
274 */
275
276 mparena *a;
277 mpw *v;
278
279 if ((f & MP_BURN) || (!undef && (m->f & MP_BURN)))
280 a = MPARENA_SECURE;
281 else
282 a = MPARENA_GLOBAL;
283 v = mpalloc(a, sz);
284
285 /* --- Copy the data over --- */
286
287 if (!undef) {
288 memcpy(v, m->v, MPWS(len));
289 if (sz - len > 0)
290 memset(v + len, 0, MPWS(sz - len));
291 }
292
293 /* --- If @m@ has other references, make a new node --- *
294 *
295 * Otherwise dispose of the old buffer.
296 */
297
298 if (!(m->f & MP_CONST) && m->ref == 1) {
299 if (m->f & MP_BURN)
300 memset(m->v, 0, MPWS(m->sz));
301 mpfree(m->a, m->v);
302 } else {
303 mp *mm = CREATE(mp);
304 mm->ref = 1;
305 mm->f = m->f;
306 m->ref--;
307 m = mm;
308 }
309
310 /* --- Fix up the node --- */
311
312 m->v = v;
313 m->vl = v + sz;
314 m->sz = sz;
315 m->f = ((m->f & ~(MP_CONST | MP_BURN)) |
316 (f & (MP_BURN | MP_UNDEF)));
317 m->a = a;
318 }
319
320 /* --- If the number is growing in its buffer, fix it up --- */
321
322 else if (sz > len) {
323 if (!undef)
324 memset(m->vl, 0, MPWS(sz - len));
325 m->vl = m->v + sz;
326 }
327 }
328
329 /* --- Done --- */
330
331 return (m);
332 }
333
334 /*----- That's all, folks -------------------------------------------------*/