X-Git-Url: https://git.distorted.org.uk/u/mdw/catacomb/blobdiff_plain/d3409d5ecf2492cff862616de72a580d1a8e8dc0..813390c45f438f411662b1a55678e63f11681eb4:/mp-mem.c diff --git a/mp-mem.c b/mp-mem.c index 2f75365..fcb6c4d 100644 --- a/mp-mem.c +++ b/mp-mem.c @@ -1,13 +1,13 @@ /* -*-c-*- * - * $Id: mp-mem.c,v 1.1 1999/11/17 18:02:16 mdw Exp $ + * $Id: mp-mem.c,v 1.8 2004/04/08 16:17:32 mdw Exp $ * * Memory management for multiprecision numbers * * (c) 1999 Straylight/Edgeware */ -/*----- Licensing notice --------------------------------------------------* +/*----- Licensing notice --------------------------------------------------* * * This file is part of Catacomb. * @@ -15,32 +15,51 @@ * it under the terms of the GNU Library General Public License as * published by the Free Software Foundation; either version 2 of the * License, or (at your option) any later version. - * + * * Catacomb 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 Library General Public License for more details. - * + * * You should have received a copy of the GNU Library General Public * License along with Catacomb; if not, write to the Free * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, * MA 02111-1307, USA. */ -/*----- Revision history --------------------------------------------------* - * - * $Log: mp-mem.c,v $ - * Revision 1.1 1999/11/17 18:02:16 mdw - * New multiprecision integer arithmetic suite. - * - */ - /*----- Header files ------------------------------------------------------*/ +#include + + #include "mp.h" /*----- Main code ---------------------------------------------------------*/ +/* --- @mp_new@ --- * + * + * Arguments: @size_t sz@ = size of vector required + * @unsigned f@ = flags to set + * + * Returns: Pointer to a new MP structure. + * + * Use: Allocates a new multiprecision integer. The data space is + * allocated from either the standard global or secret arena, + * depending on the initial flags requested. + */ + +mp *mp_new(size_t sz, unsigned f) +{ + mp *m = CREATE(mp); + m->a = (f & MP_BURN) ? MPARENA_SECURE : MPARENA_GLOBAL; + m->v = mpalloc(m->a, sz); + m->vl = m->v + sz; + m->sz = sz; + m->f = f & ~(MP_CONST | MP_DESTROYED); + m->ref = 1; + return (m); +} + /* --- @mp_create@ --- * * * Arguments: @size_t sz@ = size of vector required @@ -55,14 +74,40 @@ mp *mp_create(size_t sz) { mp *m = CREATE(mp); - m->v = MP_ALLOC(sz); + m->v = mpalloc(MPARENA_GLOBAL, sz); m->vl = m->v + sz; m->sz = sz; + m->a = MPARENA_GLOBAL; m->f = MP_UNDEF; m->ref = 1; return (m); } +/* --- @mp_createsecure@ --- * + * + * Arguments: @size_t sz@ = size of vector required + * + * Returns: Pointer to pristine new MP structure with enough memory + * bolted onto it. + * + * Use: Creates a new multiprecision integer with indeterminate + * contents. The integer has a single reference. The integer's + * data space is allocated from the secure arena. Its burn flag + * is set. + */ + +mp *mp_createsecure(size_t sz) +{ + mp *m = CREATE(mp); + m->v = mpalloc(MPARENA_SECURE, sz); + m->vl = m->v + sz; + m->sz = sz; + m->a = MPARENA_SECURE; + m->f = MP_UNDEF | MP_BURN; + m->ref = 1; + return (m); +} + /* --- @mp_build@ --- * * * Arguments: @mp *m@ = pointer to an MP block to fill in @@ -82,6 +127,7 @@ void mp_build(mp *m, mpw *v, mpw *vl) m->v = v; m->vl = vl; m->sz = vl - v; + m->a = MPARENA_GLOBAL; m->f = MP_CONST; m->ref = 1; } @@ -99,11 +145,12 @@ void mp_build(mp *m, mpw *v, mpw *vl) void mp_destroy(mp *m) { - if (m->f & MP_CONST) - return; + assert(((void)"Destroying a free integer", !(m->f & MP_DESTROYED))); + assert(((void)"Attempted to destroy a constant", !(m->f & MP_CONST))); if (m->f & MP_BURN) memset(m->v, 0, MPWS(m->sz)); - MP_FREE(m->v); + mpfree(m->a, m->v); + m->f |= MP_DESTROYED; DESTROY(m); } @@ -129,7 +176,7 @@ mp *mp_copy(mp *m) { return MP_COPY(m); } * If there are no more references, the integer is destroyed. */ -void mp_drop(mp *m) { MP_DROP(m); } +void mp_drop(mp *m) { if (m) MP_DROP(m); } /* --- @mp_split@ --- * * @@ -150,9 +197,8 @@ mp *mp_split(mp *m) { MP_SPLIT(m); return (m); } * * Returns: --- * - * Use: Resizes the vector containing the integer's digits. The new - * size must be at least as large as the current integer's - * length. This isn't really intended for client use. + * Use: Changes an integer's size. The length and value are not + * changed. It is an error to */ void mp_resize(mp *m, size_t sz) { MP_RESIZE(m, sz); } @@ -160,28 +206,131 @@ void mp_resize(mp *m, size_t sz) { MP_RESIZE(m, sz); } /* --- @mp_ensure@ --- * * * Arguments: @mp *m@ = pointer to a multiprecision integer - * @size_t sz@ = required size + * @size_t sz@ = required length * * Returns: --- * - * Use: Ensures that the integer has enough space for @sz@ digits. - * The value is not changed. + * Use: Changes an integer's length. If there is not enough space + * allocated for the new length then the size is increased. It */ void mp_ensure(mp *m, size_t sz) { MP_ENSURE(m, sz); } -/* --- @mp_modify@ --- * +/* --- @mp_dest@ --- * * - * Arguments: @mp *m@ = pointer to a multiprecision integer - * @size_t sz@ = size required + * Arguments: @mp *m@ = a suggested destination integer + * @size_t sz@ = size required for result, in digits + * @unsigned f@ = various flags + * + * Returns: A pointer to an appropriate destination. + * + * Use: Converts a suggested destination into a real destination with + * the required properties. If the real destination is @d@, + * then the following properties will hold: + * + * * @d@ will have exactly one reference. * - * Returns: Pointer to the integer (possibly different). + * * If @m@ is not @MP_NEW@, then the contents of @m@ will not + * change, unless @f@ has the @MP_UNDEF@ flag set. * - * Use: Prepares an integer to be overwritten. It's split off from - * other references to the same integer, and sufficient space is - * allocated. + * * If @m@ is not @MP_NEW@, then he reference count of @m@ on + * entry is equal to the sum of the counts of @d@ and @m@ on + * exit. + * + * * The size of @d@ will be at least @sz@. + * + * * If @f@ has the @MP_BURN@ flag set, then @d@ will be + * allocated from @MPARENA_SECURE@. + * + * Understanding this function is crucial to using Catacomb's + * multiprecision integer library effectively. */ -mp *mp_modify(mp *m, size_t sz) { MP_MODIFY(m, sz); return (m); } +mp *mp_dest(mp *m, size_t sz, unsigned f) +{ + /* --- If no destination, make one --- */ + + if (m == MP_NEWSEC) + m = mp_new(sz, f | MP_UNDEF | MP_BURN); + else if (m == MP_NEW) + m = mp_new(sz, f | MP_UNDEF); + else { + size_t len = MP_LEN(m); + unsigned undef = (m->f | f) & MP_UNDEF; + + /* --- If the value must be preserved, the block can't shrink --- */ + + if (!undef && sz < len) + sz = len; + + /* --- Otherwise check whether the destination is suitable --- */ + + if (m->ref > 1 || (m->f & MP_CONST) || + sz > m->sz || ((f & ~m->f) & MP_BURN)) { + + /* --- No -- allocate a new buffer --- * + * + * The buffer must be secure if (a) the caller requested a secure + * buffer, or (b) the old buffer is secure and I'm not allowed to + * discard the old contents. + */ + + mparena *a; + mpw *v; + + if ((f & MP_BURN) || (!undef && (m->f & MP_BURN))) + a = MPARENA_SECURE; + else + a = MPARENA_GLOBAL; + v = mpalloc(a, sz); + + /* --- Copy the data over --- */ + + if (!undef) { + memcpy(v, m->v, MPWS(len)); + if (sz - len > 0) + memset(v + len, 0, MPWS(sz - len)); + } + + /* --- If @m@ has other references, make a new node --- * + * + * Otherwise dispose of the old buffer. + */ + + if (!(m->f & MP_CONST) && m->ref == 1) { + if (m->f & MP_BURN) + memset(m->v, 0, MPWS(m->sz)); + mpfree(m->a, m->v); + } else { + mp *mm = CREATE(mp); + mm->ref = 1; + mm->f = m->f; + m->ref--; + m = mm; + } + + /* --- Fix up the node --- */ + + m->v = v; + m->vl = v + sz; + m->sz = sz; + m->f = ((m->f & ~(MP_CONST | MP_BURN)) | + (f & (MP_BURN | MP_UNDEF))); + m->a = a; + } + + /* --- If the number is growing in its buffer, fix it up --- */ + + else if (sz > len) { + if (!undef) + memset(m->vl, 0, MPWS(sz - len)); + m->vl = m->v + sz; + } + } + + /* --- Done --- */ + + return (m); +} /*----- That's all, folks -------------------------------------------------*/