mirror of
https://git.tartarus.org/simon/putty.git
synced 2025-01-09 17:38:00 +00:00
e0a76971cc
The idea of these is that they centralise the common idiom along the lines of if (logical_array_len >= physical_array_size) { physical_array_size = logical_array_len * 5 / 4 + 256; array = sresize(array, physical_array_size, ElementType); } which happens at a zillion call sites throughout this code base, with different random choices of the geometric factor and additive constant, sometimes forgetting them completely, and generally doing a lot of repeated work. The new macro sgrowarray(array,size,n) has the semantics: here are the array pointer and its physical size for you to modify, now please ensure that the nth element exists, so I can write into it. And sgrowarrayn(array,size,n,m) is the same except that it ensures that the array has size at least n+m (so sgrowarray is just the special case where m=1). Now that this is a single centralised implementation that will be used everywhere, I've also gone to more effort in the implementation, with careful overflow checks that would have been painful to put at all the previous call sites. This commit also switches over every use of sresize(), apart from a few where I really didn't think it would gain anything. A consequence of that is that a lot of array-size variables have to have their types changed to size_t, because the macros require that (they address-take the size to pass to the underlying function).
113 lines
4.4 KiB
C
113 lines
4.4 KiB
C
/*
|
|
* PuTTY memory-handling header.
|
|
*/
|
|
|
|
#ifndef PUTTY_PUTTYMEM_H
|
|
#define PUTTY_PUTTYMEM_H
|
|
|
|
#include <stddef.h> /* for size_t */
|
|
#include <string.h> /* for memcpy() */
|
|
|
|
#include "defs.h"
|
|
|
|
#define smalloc(z) safemalloc(z,1)
|
|
#define snmalloc safemalloc
|
|
#define srealloc(y,z) saferealloc(y,z,1)
|
|
#define snrealloc saferealloc
|
|
#define sfree safefree
|
|
|
|
void *safemalloc(size_t, size_t);
|
|
void *saferealloc(void *, size_t, size_t);
|
|
void safefree(void *);
|
|
|
|
/*
|
|
* Direct use of smalloc within the code should be avoided where
|
|
* possible, in favour of these type-casting macros which ensure you
|
|
* don't mistakenly allocate enough space for one sort of structure
|
|
* and assign it to a different sort of pointer. sresize also uses
|
|
* TYPECHECK to verify that the _input_ pointer is a pointer to the
|
|
* correct type.
|
|
*/
|
|
#define snew(type) ((type *)snmalloc(1, sizeof(type)))
|
|
#define snewn(n, type) ((type *)snmalloc((n), sizeof(type)))
|
|
#define sresize(ptr, n, type) TYPECHECK((type *)0 == (ptr), \
|
|
((type *)snrealloc((ptr), (n), sizeof(type))))
|
|
|
|
/*
|
|
* For cases where you want to allocate a struct plus a subsidiary
|
|
* data buffer in one step, this macro lets you add a constant to the
|
|
* amount malloced.
|
|
*
|
|
* Since the return value is already cast to the struct type, a
|
|
* pointer to that many bytes of extra data can be conveniently
|
|
* obtained by simply adding 1 to the returned pointer!
|
|
* snew_plus_get_aux is a handy macro that does that and casts the
|
|
* result to void *, so you can assign it straight to wherever you
|
|
* wanted it.
|
|
*/
|
|
#define snew_plus(type, extra) ((type *)snmalloc(1, sizeof(type) + (extra)))
|
|
#define snew_plus_get_aux(ptr) ((void *)((ptr) + 1))
|
|
|
|
/*
|
|
* Helper macros to deal with the common use case of growing an array.
|
|
*
|
|
* The common setup is that 'array' is a pointer to the first element
|
|
* of a dynamic array of some type, and 'size' represents the current
|
|
* allocated size of that array (in elements). Both of those macro
|
|
* parameters are implicitly written back to.
|
|
*
|
|
* Then sgrowarray(array, size, n) means: make sure the nth element of
|
|
* the array exists (i.e. the size is at least n+1). You call that
|
|
* before writing to the nth element, if you're looping round
|
|
* appending to the array.
|
|
*
|
|
* If you need to grow the array by more than one element, you can
|
|
* instead call sgrowarrayn(array, size, n, m), which will ensure the
|
|
* size of the array is at least n+m. (So sgrowarray is just the
|
|
* special case of that in which m == 1.)
|
|
*
|
|
* It's common to call sgrowarrayn with one of n,m equal to the
|
|
* previous logical length of the array, and the other equal to the
|
|
* new number of logical entries you want to add, so that n <= size on
|
|
* entry. But that's not actually a mandatory precondition: the two
|
|
* length parameters are just arbitrary integers that get added
|
|
* together with an initial check for overflow, and the semantics are
|
|
* simply 'make sure the array is big enough to take their sum, no
|
|
* matter how big it was to start with'.)
|
|
*
|
|
* Another occasionally useful idiom is to call sgrowarray with n ==
|
|
* size, i.e. sgrowarray(array, size, size). That just means: make
|
|
* array bigger by _some_ amount, I don't particularly mind how much.
|
|
* You might use that style if you were repeatedly calling an API
|
|
* function outside your control, which would either fill your buffer
|
|
* and return success, or else return a 'too big' error without
|
|
* telling you how much bigger it needed to be.
|
|
*/
|
|
void *safegrowarray(void *array, size_t *size, size_t eltsize,
|
|
size_t oldlen, size_t extralen);
|
|
#define sgrowarrayn(array, size, n, m) \
|
|
((array) = safegrowarray(array, &(size), sizeof(*array), n, m))
|
|
#define sgrowarray(array, size, n) sgrowarrayn(array, size, n, 1)
|
|
|
|
/*
|
|
* This function is called by the innermost safemalloc/saferealloc
|
|
* functions when allocation fails. Usually it's provided by misc.c
|
|
* which ties it into an application's existing modalfatalbox()
|
|
* system, but standalone test applications can reimplement it some
|
|
* other way if they prefer.
|
|
*/
|
|
NORETURN void out_of_memory(void);
|
|
|
|
#ifdef MINEFIELD
|
|
/*
|
|
* Definitions for Minefield, PuTTY's own Windows-specific malloc
|
|
* debugger in the style of Electric Fence. Implemented in winmisc.c,
|
|
* and referred to by the main malloc wrappers in memory.c.
|
|
*/
|
|
void *minefield_c_malloc(size_t size);
|
|
void minefield_c_free(void *p);
|
|
void *minefield_c_realloc(void *p, size_t size);
|
|
#endif
|
|
|
|
#endif
|