aboutsummaryrefslogtreecommitdiff
path: root/src/liblzma/api/lzma/memlimit.h
blob: c0449f2bd717b029dfa89d2410bf33218a699359 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/**
 * \file        lzma/memlimit.h
 * \brief       Memory usage limitter
 *
 * \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 <lzma.h> instead.
#endif


/**
 * \brief       Opaque data type used with the memory usage limitting 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 limitter functions are not tied to limitting 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);


/**
 * \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);


/**
 * \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);


/**
 * \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 limitter
 *
 * 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);


/**
 * \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);


/**
 * \brief       Removes the pointer from memory limitting 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 limitter
 *
 * \param       mem             Pointer to memory limitter
 * \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);