Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
20.temp.buffer.cpp
Go to the documentation of this file.
1
29#include <memory> // for get_temporary_buffer()
30
31#include <cerrno> // for errno
32#include <cstddef> // for ptrdiff_t, size_t
33#include <cstdio> // for sprintf()
34#include <cstring> // for memset()
35
36#ifdef _MSC_VER
37# include <climits> // for INT_MAX
38# include <crtdbg.h> // for _CrtSetReportMode()
39#endif
40
41#include <rw_new.h>
42#include <rw_printf.h>
43#include <rw_driver.h>
44
45#ifndef _RWSTD_NO_SETRLIMIT
46 // #undef works around SunPro bug #568
47# undef _TIME_T
48# include <sys/resource.h> // for setrlimit()
49# include <unistd.h> // for sbrk()
50#endif // _RWSTD_NO_SETRLIMIT
51
52#ifdef _AIX
53
54// declare the loader symbol _edata defined by the AIX loader:
55// The first address following the initialized data region.
56extern "C" {
57extern void* _edata;
58} // extern "C"
59
60#endif // _AIX
61
62
64int compare (const void *beg, const void *end, int val)
65{
66 typedef unsigned char UChar;
67
68 const UChar ucval = UChar (val);
69
70 for (const UChar *pc = (const UChar*)beg; pc != end; ++pc) {
71 if (*pc != ucval)
72 return *pc - ucval;
73 }
74
75 return 0;
76}
77
78
80template <class T>
81void test_success (T*, const char *tname)
82{
83 RW_ASSERT (0 != tname);
84
85 rw_info (0, 0, __LINE__, "std::get_temporary_buffer<%s>(ptrdiff_t)",
86 tname);
87
88 // verify that passing 0 as the argument either returns pair (0, 0)
89 // or pair (p, N) with p being a unique pointer in consecutive calls
90 // and N >= 0
91
92 static const unsigned pa_size = 32;
93
94#ifndef __HP_aCC
95
96 std::pair<T*, std::ptrdiff_t> pa [pa_size];
97
98#else // if defined (__HP_aCC)
99
100 // working around an HP aCC bug (PR #27302)
101 std::pair<T*, std::ptrdiff_t>* const pa =
102 new std::pair<T*, std::ptrdiff_t>[pa_size];
103
104#endif // __HP_aCC
105
106 // establish a checkpoint for memory leaks
107 rwt_check_leaks (0, 0);
108
109 pa [0] = std::get_temporary_buffer<T>(0);
110
111 if (pa [0].first) {
112
113 std::memset (pa [0].first, ~0U, pa [0].second * sizeof (T));
114
115 pa [1] = std::get_temporary_buffer<T>(0);
116
117 if (pa [1].first)
118 std::memset (pa [1].first, ~1U, pa [1].second * sizeof (T));
119
120 rw_assert (pa [0].first != pa [1].first, 0, __LINE__,
121 "get_temporary_buffer<%s>(0).first not unique: "
122 "got %#p and %#p", tname, pa [0].first, pa [1].first);
123 }
124 else {
125 rw_assert (0 == pa [0].second, 0, __LINE__,
126 "get_temporary_buffer<%s>(0) == { 0, 0 }, got "
127 "{ %#p, %td }", tname, pa [0].first, pa [0].second);
128 }
129
130 pa [2] = std::get_temporary_buffer<T>(2);
131
132 rw_assert (0 != pa [2].first, 0, __LINE__,
133 "get_temporary_buffer<%s>(2).first != 0, got 0", tname);
134
135 if (0 == pa [2].first)
136 return;
137
138 std::memset (pa [2].first, ~2U, pa [2].second * sizeof (T));
139
140 rw_assert (2 <= pa [2].second, 0, __LINE__,
141 "get_temporary_buffer<%s>(2).second >= 2, got %td",
142 tname, pa [2].second);
143
144 pa [3] = std::get_temporary_buffer<T>(3);
145
146
147 rw_assert (0 != pa [3].first, 0, __LINE__,
148 "get_temporary_buffer<%s>(3).first != 0, got 0", tname);
149
150 if (!pa [3].first)
151 return;
152
153 rw_assert (3 <= pa [3].second, 0, __LINE__,
154 "get_temporary_buffer<%s>(3).second >= 3, got %td",
155 tname, pa [3].second);
156
157 // verify correct alignment (if the storage isn't properly aligned,
158 // expect SIGBUS on RISC machines, or SIGSEGV on HP-UX/PA-RISC)
159 pa [3].first [0] = T ();
160 pa [3].first [1] = T ();
161 pa [3].first [2] = T ();
162
163 std::memset (pa [3].first, ~3U, pa [3].second * sizeof (T));
164
165 // get the remaining temporary buffers and verify that they
166 // are each distinct from one another
167 for (unsigned i = 4; i != pa_size; ++i) {
168
169 const std::ptrdiff_t size =
170 std::ptrdiff_t (i % 2 ? i : _RWSTD_TMPBUF_SIZE + i);
171
172 pa [i] = std::get_temporary_buffer<T>(size);
173
174 if (pa [i].first)
175 std::memset (pa [i].first, ~i, pa [i].second * sizeof (T));
176 }
177
178 // verify the uniqueness of all ranges
179 for (unsigned i = 0; i < pa_size; ++i) {
180 for (unsigned j = 0; j < pa_size; ++j) {
181 const bool fail =
182 i != j && pa [i].first
183 && pa [i].first >= pa [j].first
184 && pa [i].first < pa [j].first + pa [j].second;
185
186 rw_assert (!fail, 0, __LINE__,
187 "pair { %#p, %td } returned from call %u overlaps "
188 "pair { %#p, %td } returned from call %u",
189 pa [i].first, pa [i].second, i,
190 pa [j].first, pa [j].second, j);
191
192 if (fail) {
193 // break out of both loops
194 i = j = unsigned (-1);
195 }
196 }
197 }
198
199 rw_info (0, 0, __LINE__,
200 "std::return_temporary_buffer<%s>(%1$s*)", tname);
201
202 // call return_temporary_buffer() on each returned pointer
203 // and verify that the contents of the buffers pointed to
204 // by all remaining unallocated pointers are unchanged
205 for (unsigned i = 0; i < pa_size; ++i) {
206
207 std::return_temporary_buffer (pa [i].first);
208
209 for (unsigned j = i + 1; j < pa_size; ++j) {
210
211 const bool success =
212 0 == compare (pa [j].first, pa [j].first + pa [j].second, ~j);
213
214 rw_assert (success, 0, __LINE__,
215 "return_temporary_buffer<%s>(%#p) corrupted "
216 "a buffer designated by { %#p %td }",
217 tname, pa [i].first, pa [j].first, pa [j].second);
218
219 if (!success) {
220 // break out of both loops
221 i = j = unsigned (-1);
222 }
223 }
224 }
225
226 std::size_t nbytes;
227 const std::size_t nblocks = rwt_check_leaks (&nbytes, 0);
228
229 // verify the absence of memory leaks
230 rw_assert (!nblocks && !nbytes, 0, __LINE__,
231 "temporary buffer leaked %d bytes in %d blocks",
232 nbytes, nblocks);
233
234#ifdef __HP_aCC
235
236 delete[] pa;
237
238#endif // __HP_aCC
239
240}
241
242
244template <class T>
245void test_failure (T*, const char *tname)
246{
247 if (0 == tname) {
248 static char buf [40];
249 rw_sprintf (buf, "char[%zu]", sizeof (T));
250 tname = buf;
251 }
252
253 rw_info (0, 0, __LINE__,
254 "std::get_temporary_buffer<%s>(ptrdiff_t) on arithmetic overflow",
255 tname);
256
257 std::ptrdiff_t nelems = -1;
258
259 std::pair<T*, std::ptrdiff_t> pa;
260
261 pa = std::get_temporary_buffer<T>(nelems);
262
263 rw_assert (0 == pa.first && 0 == pa.second, 0, __LINE__,
264 "std::get_temporary_buffer<%s>(%td) == { 0, 0 }, "
265 "got { %#p, %td }",
266 tname, nelems, pa.first, pa.second);
267
268 for (std::size_t i = 2; i && i < sizeof (T); i <<= 1) {
269 // exercise arithmetic overflow (not to be confused
270 // with the out-of-memory tests below)
271
272 // attempts to allocate space for an array of elements
273 // with a total size that exceeds SIZE_MAX must fail
274 nelems = (_RWSTD_PTRDIFF_MAX / i) + 1;
275
276 pa = std::get_temporary_buffer<T>(nelems);
277
278 rw_assert (0 == pa.first && 0 == pa.second, 0, __LINE__,
279 "get_temporary_buffer<%s>(%ld) == { 0, 0 }, "
280 "got { %#p, %td }",
281 tname, nelems, pa.first, pa.second);
282 }
283
284#ifndef _RWSTD_NO_SETRLIMIT
285
286 // exercise get_temporary_buffer in the presence of allocation
287 // failure (caused by setting the soft data limit to the current
288 // value)
289
290 // retrieve the current soft (rlim_cur) and hard (rlim_max) limits
291 struct rlimit rlim_old;
292 if (getrlimit (RLIMIT_DATA, &rlim_old)) {
293 rw_warn (0, 0, __LINE__,
294 "getrlimit(RLIMIT_DATA, { .rlim_max=%zu, .rlim_cur=%zu}) "
295 "failed: %{#m}: %m", rlim_old.rlim_max, rlim_old.rlim_cur);
296 return;
297 }
298
299 // set the soft limit to 0, leaving the hard limit unchanged
300 struct rlimit rlim_new = rlim_old;
301
302#ifdef _AIX
303 {
304 // AIX setrlimit() fails to lower the limit for resource
305 // whose current usage is already higher than the new limit.
306 // Instead of setting the limit to 0, compute the current
307 // usage and use it to set the soft limit
308 const char* const brk_min = (char*)_edata;
309 const char* const brk_cur = (char*)sbrk (0);
310
311 rlim_new.rlim_cur = brk_cur - brk_min;
312 }
313#else // if !defined (_AIX)
314 rlim_new.rlim_cur = 0;
315#endif // _AIX
316
317 errno = 0;
318
319 // IEEE Std 1003.1, 2004 Edition (SUSv3):
320 // RLIMIT_DATA
321 // ...is the maximum size of a process' data segment, in bytes.
322 // If this limit is exceeded, the malloc() function shall fail
323 // with errno set to [ENOMEM].
324 if (setrlimit (RLIMIT_DATA, &rlim_new)) {
325 rw_warn (0, 0, __LINE__,
326 "setrlimit(RLIMIT_DATA, { .rlim_max=%zu, .rlim_cur=%zu}) "
327 "failed to lower the soft limit: %{#m}: %m",
328 rlim_new.rlim_max, rlim_new.rlim_cur);
329 return;
330 }
331
332 std::size_t nbytes = rlim_old.rlim_max;
333
334#if 0 < _RWSTD_TMPBUF_SIZE
335
336 // make sure the size is larger than the size of the temp buff
337 if (nbytes <= _RWSTD_TMPBUF_SIZE)
338 nbytes = _RWSTD_TMPBUF_SIZE + 1;
339
340#else // if _RWSTD_TMPBUF_SIZE <= 0
341
342 nbytes = 65536;
343
344#endif // _RWSTD_TMPBUF_SIZE
345
346 if (nbytes < _RWSTD_SIZE_MAX)
347 ++nbytes;
348
349 if (nbytes <= std::size_t (_RWSTD_PTRDIFF_MAX))
350 nelems = std::ptrdiff_t (nbytes);
351 else
352 nelems = _RWSTD_PTRDIFF_MAX;
353
354 nelems /= sizeof (T);
355
356 // retrieve the current limit just to show it in the info message
357 // ignore any errors
358 getrlimit (RLIMIT_DATA, &rlim_new);
359
360 rw_info (0, 0, __LINE__,
361 "std::get_temporary_buffer<%s>(%td) in low memory conditions "
362 ": { .rlim_max = %zu, .rlim_cur = %zu }",
363 tname, nelems, rlim_new.rlim_max, rlim_new.rlim_cur);
364
365 // expect the function to fail
366 pa = std::get_temporary_buffer<T>(nelems);
367
368 // reset the soft limit to the original value (do it before any
369 // test output in case memory needs to be allocated during the
370 // output)
371 if (setrlimit (RLIMIT_DATA, &rlim_old)) {
372 rw_warn (0, 0, __LINE__,
373 "setrlimit(RLIMIT_DATA, { .rlim_max=%zu, .rlim_cur=%zu }) "
374 "failed to restore the soft limit: %{#m}: %m",
375 rlim_old.rlim_max, rlim_old.rlim_cur);
376 }
377
378 rw_assert (0 == pa.first && 0 == pa.second, 0, __LINE__,
379 "get_temporary_buffer<%s>(%td) == { 0, 0 } "
380 "in low memory conditions, got { %#p, %td }",
381 tname, nbytes, pa.first, pa.second);
382
383#endif // _RWSTD_NO_SETRLIMIT
384
385}
386
387
389typedef void (*FunctionPointer)();
390
391struct MyStruct { };
392typedef void (MyStruct::*MemberPointer)();
393
394template <std::size_t N>
395struct BigStruct { char dummy [N]; };
396
397
399template <class T>
400void test_get_temporary_buffer (T *dummy, const char *tname)
401{
402 RW_ASSERT (0 != tname);
403
404 test_success (dummy, tname);
405 test_failure (dummy, tname);
406}
407
408
410static int
411run_test (int, char**)
412{
413 test_get_temporary_buffer ((char*)0, "char");
414
415 test_get_temporary_buffer ((int*)0, "int");
416
417#ifdef _RWSTD_LONG_LONG
418
420
421#else // if !defined (_RWSTD_LONG_LONG)
422
423 test_get_temporary_buffer ((long*)0, "long");
424
425#endif // _RWSTD_LONG_LONG
426
427#ifndef _RWSTD_NO_LONG_DOUBLE
428
429 test_get_temporary_buffer ((long double*)0, "long double");
430
431#else // if defined (_RWSTD_NO_LONG_DOUBLE)
432
433 test_get_temporary_buffer ((double*)0, "double");
434
435#endif // _RWSTD_NO_LONG_DOUBLE
436
437 // exercise ordinary pointers
438 test_get_temporary_buffer ((void**)0, "void*");
439
440 // exercise function pointers
441 test_get_temporary_buffer ((FunctionPointer*)0, "void (*)()");
442
443 // exercise pointers to members
444 test_get_temporary_buffer ((MemberPointer*)0, "void (struct::*)()");
445
446#if (!defined (__IBMCPP__) || __IBMCPP__ > 700) \
447 && !defined (__HP_aCC)
448
449# ifndef _MSC_VER
450 const std::size_t MAX_SIZE = _RWSTD_PTRDIFF_MAX;
451# else
452 // the MSVC and ICC/Windows has maximum size of
453 // the array equal to 0x7fffffff bytes
454 const std::size_t MAX_SIZE = INT_MAX;
455# endif
456
457 // avoid instantiating test on very large structs
458 // to prevent failures (at compile or run-time) due
459 // to compiler bugs
463
464#else
465
466 // work around VAC++ 7.0 (and prior) bug #549
467 // work around HP aCC 3,5,6 bug #565
468 rw_warn (0, 0, __LINE__, "get_temp_buffer<large-struct>() "
469 "not tested due to a compiler bug");
470
471#endif // VAC++ > 7.0
472
473 return 0;
474}
475
476
478int main (int argc, char *argv[])
479{
480#ifdef _MSC_VER
481 // disable "Invalid allocation size: 4294967292 bytes"
482 // message box from malloc()
483 _CrtSetReportMode (_CRT_ERROR, _CRTDBG_MODE_DEBUG);
484#endif
485
486 return rw_test (argc, argv, __FILE__,
487 "lib.temporary.buffer",
488 0 /* no comment */,
489 run_test,
490 "",
491 (void*)0 /* sentinel */);
492}
int fail
#define N
Definition 17.names.cpp:157
#define i
Definition 17.names.cpp:126
#define T
Definition 17.names.cpp:163
#define buf
Definition 17.names.cpp:452
#define j
Definition 17.names.cpp:127
#define val
Definition 17.names.cpp:570
#define U
Definition 17.names.cpp:164
void test_get_temporary_buffer(T *dummy, const char *tname)
void(MyStruct::* MemberPointer)()
void test_success(T *, const char *tname)
void(* FunctionPointer)()
void test_failure(T *, const char *tname)
void run_test(const ForwardIterator &dummy, T *, Predicate *pred)
const int end
#define main
#define _RWSTD_LONG_LONG
#define _RWSTD_TMPBUF_SIZE
Definition _defs.h:1309
#define INT_MAX
Definition limits.h:76
_TEST_EXPORT int rw_test(int argc, char *argv[], const char *filename, const char *clause, const char *comment, int(*testfun)(int, char **), const char *optspec,...)
_TEST_EXPORT int rw_info(int, const char *, int, const char *,...)
Definition driver.cpp:1681
_TEST_EXPORT int rw_assert(int, const char *, int, const char *,...)
Definition driver.cpp:1630
_TEST_EXPORT int rw_warn(int, const char *, int, const char *,...)
Definition driver.cpp:1647
_TEST_EXPORT _RWSTD_SIZE_T rwt_check_leaks(_RWSTD_SIZE_T *, const rwt_free_store *)
Definition new.cpp:684
_TEST_EXPORT int rw_sprintf(char *, const char *,...)
Definition printf.cpp:3284
#define RW_ASSERT(expr)
unsigned char UChar
Definition collate.cpp:122