/** * \file lzma/memlimit.h * \brief Memory usage limiter * * \author Copyright (C) 1999-2006 Igor Pavlov * \author Copyright (C) 2007 Lasse Collin * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. */ #ifndef LZMA_H_INTERNAL # error Never include this file directly. Use instead. #endif /** * \brief Opaque data type used with the memory usage limiting functions */ typedef struct lzma_memlimit_s lzma_memlimit; /** * \brief Allocates and initializes a new lzma_memlimit structure * * It is easy to make liblzma to use huge amounts of memory. This can * be a problem especially with the decoder, since it a file requiring * huge amounts of memory to uncompress could allow even a denial of * service attack if the memory usage wasn't limited. * * liblzma provides a set of functions to control memory usage. Pointers * to these functions can be used in lzma_allocator structure, which makes * it easy to limit memory usage with liblzma. * * The memory limiter functions are not tied to limiting memory usage * with liblzma itself. You can use them with anything you like. * * In multi-threaded applications, only one thread at once may use the same * lzma_memlimit structure. If there is a need, this limitation may * be removed in future versions without breaking the libary API/ABI. * * \param limit Initial memory usage limit in bytes * * \return Pointer to allocated and initialized lzma_memlimit * structure. On error, NULL is returned. The reason behind * an error is either that malloc() failed or that the given * limit was so small that it didn't allow allocating even * the lzma_memlimit structure itself. * * \note Excluding lzma_memlimit_usage(), the functions whose name begin * lzma_memlimit_ can be used even if lzma_init() hasn't been * called. */ extern lzma_memlimit *lzma_memlimit_create(size_t limit) lzma_attr_warn_unused_result; /** * \brief Sets a new memory usage limit * * \param mem Pointer to a lzma_memlimit structure returned * earlier by lzma_memry_limit_create(). * \param limit New memory usage limit * * The new usage limit may be smaller than the amount of memory currently * allocated via *mem: New allocations will fail until enough memory has * been freed or a new limit is set, but the existing allocatations will * stay untouched. */ extern void lzma_memlimit_set(lzma_memlimit *mem, size_t limit); /** * \brief Gets the current memory usage limit */ extern size_t lzma_memlimit_get(const lzma_memlimit *mem) lzma_attr_pure; /** * \brief Gets the amount of currently allocated memory * * \note This value includes the sizes of some helper structures, * thus it will always be larger than the total number of * bytes allocated via lzma_memlimit_alloc(). */ extern size_t lzma_memlimit_used(const lzma_memlimit *mem) lzma_attr_pure; /** * \brief Gets the maximum amount of memory required in total * * Returns how much memory was or would have been allocated at the same time. * If lzma_memlimit_alloc() was requested so much memory that the limit * would have been exceeded or malloc() simply ran out of memory, the * requested amount is still included to the value returned by * lzma_memlimit_max(). This may be used as a hint how much bigger memory * limit would have been needed. * * If the clear flag is set, the internal variable holding the maximum * value is set to the current memory usage (the same value as returned * by lzma_memlimit_used()). * * \note Usually liblzma needs to allocate many chunks of memory, and * displaying a message like "memory usage limit reached, at * least 1024 bytes would have been needed" may be confusing, * because the next allocation could have been e.g. 8 MiB. * * \todo The description of this function is unclear. */ extern size_t lzma_memlimit_max(lzma_memlimit *mem, lzma_bool clear); /** * \brief Checks if memory limit was reached at some point * * This function is useful to find out if the reason for LZMA_MEM_ERROR * was running out of memory or hitting the memory usage limit imposed * by lzma_memlimit_alloc(). If the clear argument is true, the internal * flag, that indicates that limit was reached, is cleared. */ extern lzma_bool lzma_memlimit_reached(lzma_memlimit *mem, lzma_bool clear); /** * \brief Gets the number of allocations owned by the memory limiter * * The count does not include the helper structures; if no memory has * been allocated with lzma_memlimit_alloc() or all memory allocated * has been freed or detached, this will return zero. */ extern size_t lzma_memlimit_count(const lzma_memlimit *mem) lzma_attr_pure; /** * \brief Allocates memory with malloc() if memory limit allows * * \param mem Pointer to a lzma_memlimit structure returned * earlier by lzma_memry_limit_create(). * \param nmemb Number of elements to allocate. While liblzma always * sets this to one, this function still takes the * value of nmemb into account to keep the function * usable with zlib and libbzip2. * \param size Size of an element. * * \return Pointer to memory allocated with malloc(nmemb * size), * except if nmemb * size == 0 which returns malloc(1). * On error, NULL is returned. * * \note This function assumes that nmemb * size is at maximum of * SIZE_MAX. If it isn't, an overflow will occur resulting * invalid amount of memory being allocated. */ extern void *lzma_memlimit_alloc( lzma_memlimit *mem, size_t nmemb, size_t size) lzma_attr_warn_unused_result; /** * \brief Removes the pointer from memory limiting list * * \param mem Pointer to a lzma_memlimit structure returned * earlier by lzma_memry_limit_create(). * \param ptr Pointer returned earlier by lzma_memlimit_alloc(). * * This function removes ptr from the internal list and decreases the * counter of used memory accordingly. The ptr itself isn't freed. This is * useful when Extra Records allocated by liblzma using lzma_memlimit * are needed by the application and must not be freed when the * lzma_memlimit structure is destroyed. * * It is OK to call this function with ptr that hasn't been allocated with * lzma_memlimit_alloc(). In that case, this has no effect other than wasting * a few CPU cycles. */ extern void lzma_memlimit_detach(lzma_memlimit *mem, void *ptr); /** * \brief Frees memory and updates the memory limit list * * This is like lzma_memlimit_detach() but also frees the given pointer. */ extern void lzma_memlimit_free(lzma_memlimit *mem, void *ptr); /** * \brief Frees the memory allocated for and by the memory usage limiter * * \param mem Pointer to memory limiter * \param free_allocated If this is non-zero, all the memory allocated * by lzma_memlimit_alloc() using *mem is also * freed if it hasn't already been freed with * lzma_memlimit_free(). Usually this should be * set to true. */ extern void lzma_memlimit_end( lzma_memlimit *mem, lzma_bool free_allocated);