1 | /* |
2 | * gmem.h |
3 | * |
4 | * Memory routines with out-of-memory checking. |
5 | * |
6 | * Copyright 1996-2003 Glyph & Cog, LLC |
7 | */ |
8 | |
9 | //======================================================================== |
10 | // |
11 | // Modified under the Poppler project - http://poppler.freedesktop.org |
12 | // |
13 | // All changes made under the Poppler project to this file are licensed |
14 | // under GPL version 2 or later |
15 | // |
16 | // Copyright (C) 2005 Takashi Iwai <tiwai@suse.de> |
17 | // Copyright (C) 2007-2010, 2017, 2019, 2022 Albert Astals Cid <aacid@kde.org> |
18 | // Copyright (C) 2008 Jonathan Kew <jonathan_kew@sil.org> |
19 | // Copyright (C) 2018 Adam Reichold <adam.reichold@t-online.de> |
20 | // Copyright (C) 2021 Even Rouault <even.rouault@spatialys.com> |
21 | // |
22 | // To see a description of the changes please see the Changelog file that |
23 | // came with your tarball or type make ChangeLog if you are building from git |
24 | // |
25 | //======================================================================== |
26 | |
27 | #ifndef GMEM_H |
28 | #define GMEM_H |
29 | |
30 | #include <cassert> |
31 | #include <cstring> |
32 | #include <cstdlib> |
33 | #include <cstdio> |
34 | |
35 | #include "GooCheckedOps.h" |
36 | |
37 | /// Same as malloc, but prints error message and exits if malloc() returns NULL. |
38 | inline void *gmalloc(size_t size, bool checkoverflow = false) |
39 | { |
40 | if (size == 0) { |
41 | return nullptr; |
42 | } |
43 | |
44 | if (void *p = std::malloc(size: size)) { |
45 | return p; |
46 | } |
47 | |
48 | std::fputs(s: "Out of memory\n" , stderr); |
49 | |
50 | if (checkoverflow) { |
51 | return nullptr; |
52 | } |
53 | |
54 | std::abort(); |
55 | } |
56 | |
57 | inline void *gmalloc_checkoverflow(size_t size) |
58 | { |
59 | return gmalloc(size, checkoverflow: true); |
60 | } |
61 | |
62 | /// Same as free |
63 | inline void gfree(void *p) |
64 | { |
65 | std::free(ptr: p); |
66 | } |
67 | |
68 | /// Same as realloc, but prints error message and exits if realloc() returns NULL. |
69 | /// If <p> is NULL, calls malloc() instead of realloc(). |
70 | inline void *grealloc(void *p, size_t size, bool checkoverflow = false) |
71 | { |
72 | if (size == 0) { |
73 | gfree(p); |
74 | return nullptr; |
75 | } |
76 | |
77 | if (void *q = p ? std::realloc(ptr: p, size: size) : std::malloc(size: size)) { |
78 | return q; |
79 | } |
80 | |
81 | std::fputs(s: "Out of memory\n" , stderr); |
82 | |
83 | if (checkoverflow) { |
84 | return nullptr; |
85 | } |
86 | |
87 | std::abort(); |
88 | } |
89 | |
90 | inline void *grealloc_checkoverflow(void *p, size_t size) |
91 | { |
92 | return grealloc(p, size, checkoverflow: true); |
93 | } |
94 | |
95 | /* |
96 | * These are similar to gmalloc and grealloc, but take an object count |
97 | * and size. The result is similar to allocating <count> * <size> |
98 | * bytes, but there is an additional error check that the total size |
99 | * doesn't overflow an int. |
100 | * The gmallocn_checkoverflow variant returns NULL instead of exiting |
101 | * the application if a overflow is detected. |
102 | */ |
103 | |
104 | inline void *gmallocn(int count, int size, bool checkoverflow = false) |
105 | { |
106 | if (count == 0) { |
107 | return nullptr; |
108 | } |
109 | |
110 | int bytes; |
111 | if (count < 0 || size <= 0 || checkedMultiply(x: count, y: size, z: &bytes)) { |
112 | std::fputs(s: "Bogus memory allocation size\n" , stderr); |
113 | |
114 | if (checkoverflow) { |
115 | return nullptr; |
116 | } |
117 | |
118 | std::abort(); |
119 | } |
120 | |
121 | return gmalloc(size: bytes, checkoverflow); |
122 | } |
123 | |
124 | inline void *gmallocn_checkoverflow(int count, int size) |
125 | { |
126 | return gmallocn(count, size, checkoverflow: true); |
127 | } |
128 | |
129 | inline void *gmallocn3(int width, int height, int size, bool checkoverflow = false) |
130 | { |
131 | if (width == 0 || height == 0) { |
132 | return nullptr; |
133 | } |
134 | |
135 | int count; |
136 | int bytes; |
137 | if (width < 0 || height < 0 || size <= 0 || checkedMultiply(x: width, y: height, z: &count) || checkedMultiply(x: count, y: size, z: &bytes)) { |
138 | std::fputs(s: "Bogus memory allocation size\n" , stderr); |
139 | |
140 | if (checkoverflow) { |
141 | return nullptr; |
142 | } |
143 | |
144 | std::abort(); |
145 | } |
146 | |
147 | return gmalloc(size: bytes, checkoverflow); |
148 | } |
149 | |
150 | inline void *greallocn(void *p, int count, int size, bool checkoverflow = false, bool free_p = true) |
151 | { |
152 | if (count == 0) { |
153 | if (free_p) { |
154 | gfree(p); |
155 | } |
156 | return nullptr; |
157 | } |
158 | |
159 | int bytes; |
160 | if (count < 0 || size <= 0 || checkedMultiply(x: count, y: size, z: &bytes)) { |
161 | std::fputs(s: "Bogus memory allocation size\n" , stderr); |
162 | |
163 | if (checkoverflow) { |
164 | if (free_p) { |
165 | gfree(p); |
166 | } |
167 | return nullptr; |
168 | } |
169 | |
170 | std::abort(); |
171 | } |
172 | |
173 | assert(bytes > 0); |
174 | if (void *q = grealloc(p, size: bytes, checkoverflow)) { |
175 | return q; |
176 | } |
177 | if (free_p) { |
178 | gfree(p); |
179 | } |
180 | return nullptr; |
181 | } |
182 | |
183 | inline void *greallocn_checkoverflow(void *p, int count, int size) |
184 | { |
185 | return greallocn(p, count, size, checkoverflow: true); |
186 | } |
187 | |
188 | /// Allocate memory and copy a string into it. |
189 | inline char *copyString(const char *s) |
190 | { |
191 | char *r = static_cast<char *>(gmalloc(size: std::strlen(s: s) + 1, checkoverflow: false)); |
192 | return std::strcpy(dest: r, src: s); |
193 | } |
194 | |
195 | /// Allocate memory and copy a limited-length string to it. |
196 | inline char *copyString(const char *s, size_t n) |
197 | { |
198 | char *r = static_cast<char *>(gmalloc(size: n + 1, checkoverflow: false)); |
199 | r[n] = '\0'; |
200 | return std::strncpy(dest: r, src: s, n: n); |
201 | } |
202 | |
203 | #endif // GMEM_H |
204 | |