150
|
1 // RUN: %clangxx_scudo %s -lstdc++ -o %t
|
|
2 // RUN: %run %t pointers 2>&1
|
|
3 // RUN: %run %t contents 2>&1
|
|
4 // RUN: %run %t usablesize 2>&1
|
|
5
|
|
6 // Tests that our reallocation function returns the same pointer when the
|
|
7 // requested size can fit into the previously allocated chunk. Also tests that
|
|
8 // a new chunk is returned if the size is greater, and that the contents of the
|
|
9 // chunk are left unchanged. Finally, checks that realloc copies the usable
|
|
10 // size of the old chunk to the new one (as opposed to the requested size).
|
|
11
|
|
12 #include <assert.h>
|
|
13 #include <malloc.h>
|
|
14 #include <string.h>
|
|
15
|
|
16 #include <vector>
|
|
17
|
|
18 #include <sanitizer/allocator_interface.h>
|
|
19
|
221
|
20 int main(int argc, char **argv) {
|
150
|
21 void *p, *old_p;
|
|
22 // Those sizes will exercise both allocators (Primary & Secondary).
|
|
23 std::vector<size_t> sizes{1, 16, 1024, 32768, 1 << 16, 1 << 17, 1 << 20};
|
|
24
|
|
25 assert(argc == 2);
|
|
26
|
|
27 if (!strcmp(argv[1], "usablesize")) {
|
|
28 // This tests a sketchy behavior inherited from poorly written libraries
|
|
29 // that have become somewhat standard. When realloc'ing a chunk, the
|
|
30 // copied contents should span the usable size of the chunk, not the
|
|
31 // requested size.
|
|
32 size_t size = 496, usable_size;
|
|
33 p = nullptr;
|
|
34 // Make sure we get a chunk with a usable size actually larger than size.
|
|
35 do {
|
221
|
36 if (p)
|
|
37 free(p);
|
150
|
38 size += 16;
|
|
39 p = malloc(size);
|
|
40 usable_size = __sanitizer_get_allocated_size(p);
|
|
41 assert(usable_size >= size);
|
|
42 } while (usable_size == size);
|
|
43 for (int i = 0; i < usable_size; i++)
|
|
44 reinterpret_cast<char *>(p)[i] = 'A';
|
|
45 old_p = p;
|
|
46 // Make sure we get a different chunk so that the data is actually copied.
|
|
47 do {
|
|
48 size *= 2;
|
|
49 p = realloc(p, size);
|
|
50 assert(p);
|
|
51 } while (p == old_p);
|
|
52 // The contents of the new chunk must match the old one up to usable_size.
|
|
53 for (int i = 0; i < usable_size; i++)
|
|
54 assert(reinterpret_cast<char *>(p)[i] == 'A');
|
|
55 free(p);
|
|
56 } else {
|
|
57 for (size_t size : sizes) {
|
|
58 if (!strcmp(argv[1], "pointers")) {
|
|
59 old_p = p = realloc(nullptr, size);
|
|
60 assert(p);
|
|
61 size = __sanitizer_get_allocated_size(p);
|
|
62 // Our realloc implementation will return the same pointer if the size
|
|
63 // requested is lower than or equal to the usable size of the associated
|
|
64 // chunk.
|
|
65 p = realloc(p, size - 1);
|
|
66 assert(p == old_p);
|
|
67 p = realloc(p, size);
|
|
68 assert(p == old_p);
|
|
69 // And a new one if the size is greater.
|
|
70 p = realloc(p, size + 1);
|
|
71 assert(p != old_p);
|
|
72 // A size of 0 will free the chunk and return nullptr.
|
|
73 p = realloc(p, 0);
|
|
74 assert(!p);
|
|
75 old_p = nullptr;
|
|
76 }
|
|
77 if (!strcmp(argv[1], "contents")) {
|
|
78 p = realloc(nullptr, size);
|
|
79 assert(p);
|
|
80 for (int i = 0; i < size; i++)
|
|
81 reinterpret_cast<char *>(p)[i] = 'A';
|
|
82 p = realloc(p, size + 1);
|
|
83 // The contents of the reallocated chunk must match the original one.
|
|
84 for (int i = 0; i < size; i++)
|
|
85 assert(reinterpret_cast<char *>(p)[i] == 'A');
|
|
86 }
|
|
87 }
|
|
88 }
|
|
89 return 0;
|
|
90 }
|
|
91
|
|
92 // CHECK: ERROR: invalid chunk type when reallocating address
|