Here is a test for memwipe.
[tor.git] / src / test / test-memwipe.c
bloba721a8e728f8377db43b9865c0a6c92723b40cb8
1 #include <string.h>
2 #include <stdio.h>
3 #include <sys/types.h>
4 #include <stdlib.h>
6 #include "crypto.h"
7 #include "compat.h"
9 #undef MIN
10 #define MIN(a,b) ( ((a)<(b)) ? (a) : (b) )
12 static unsigned fill_a_buffer_memset(void) __attribute__((noinline));
13 static unsigned fill_a_buffer_memwipe(void) __attribute__((noinline));
14 static unsigned fill_a_buffer_nothing(void) __attribute__((noinline));
15 static unsigned fill_heap_buffer_memset(void) __attribute__((noinline));
16 static unsigned fill_heap_buffer_memwipe(void) __attribute__((noinline));
17 static unsigned fill_heap_buffer_nothing(void) __attribute__((noinline));
18 static unsigned check_a_buffer(void) __attribute__((noinline));
20 const char *s = NULL;
22 #define FILL_BUFFER_IMPL() \
23 unsigned int i; \
24 unsigned sum = 0; \
26 /* Fill up a 1k buffer with a recognizable pattern. */ \
27 for (i = 0; i < 2048; i += strlen(s)) { \
28 memcpy(buf+i, s, MIN(strlen(s), 2048-i)); \
29 } \
31 /* Use the buffer as input to a computation so the above can't get */ \
32 /* optimized away. */ \
33 for (i = 0; i < 2048; ++i) { \
34 sum += (unsigned char)buf[i]; \
37 static unsigned
38 fill_a_buffer_memset(void)
40 char buf[2048];
41 FILL_BUFFER_IMPL()
42 memset(buf, 0, sizeof(buf));
43 return sum;
46 static unsigned
47 fill_a_buffer_memwipe(void)
49 char buf[2048];
50 FILL_BUFFER_IMPL()
51 memwipe(buf, 0, sizeof(buf));
52 return sum;
55 static unsigned
56 fill_a_buffer_nothing(void)
58 char buf[2048];
59 FILL_BUFFER_IMPL()
60 return sum;
63 static INLINE int
64 vmemeq(volatile char *a, const char *b, size_t n)
66 while (n--) {
67 if (*a++ != *b++)
68 return 0;
70 return 1;
73 static unsigned
74 check_a_buffer(void)
76 unsigned int i;
77 volatile char buf[1024];
78 unsigned sum = 0;
80 /* See if this buffer has the string in it.
82 YES, THIS DOES INVOKE UNDEFINED BEHAVIOR BY READING FROM AN UNINITIALIZED
83 BUFFER.
85 If you know a better way to figure out whether the compiler eliminated
86 the memset/memwipe calls or not, please let me know.
88 for (i = 0; i < sizeof(buf); ++i) {
89 if (vmemeq(buf+i, s, strlen(s)))
90 ++sum;
93 return sum;
96 static char *heap_buf = NULL;
98 static unsigned
99 fill_heap_buffer_memset(void)
101 char *buf = heap_buf = malloc(2048);
102 FILL_BUFFER_IMPL()
103 memset(buf, 0, 2048);
104 free(buf);
105 return sum;
108 static unsigned
109 fill_heap_buffer_memwipe(void)
111 char *buf = heap_buf = malloc(2048);
112 FILL_BUFFER_IMPL()
113 memwipe(buf, 0, 2048);
114 free(buf);
115 return sum;
118 static unsigned
119 fill_heap_buffer_nothing(void)
121 char *buf = heap_buf = malloc(2048);
122 FILL_BUFFER_IMPL()
123 free(buf);
124 return sum;
127 static unsigned
128 check_heap_buffer(void)
130 unsigned int i;
131 unsigned sum = 0;
132 volatile char *buf = heap_buf;
134 /* See if this buffer has the string in it.
136 YES, THIS DOES INVOKE UNDEFINED BEHAVIOR BY READING FROM A FREED BUFFER.
138 If you know a better way to figure out whether the compiler eliminated
139 the memset/memwipe calls or not, please let me know.
141 for (i = 0; i < sizeof(buf); ++i) {
142 if (vmemeq(buf+i, s, strlen(s)))
143 ++sum;
146 return sum;
149 static struct testcase {
150 const char *name;
151 unsigned (*fill_fn)(void);
152 unsigned (*check_fn)(void);
153 } testcases[] = {
154 { "nil", fill_a_buffer_nothing, check_a_buffer },
155 { "nil-heap", fill_heap_buffer_nothing, check_heap_buffer },
156 { "memset", fill_a_buffer_memset, check_a_buffer },
157 { "memset-heap", fill_heap_buffer_memset, check_heap_buffer },
158 { "memwipe", fill_a_buffer_memwipe, check_a_buffer },
159 { "memwipe-heap", fill_heap_buffer_memwipe, check_heap_buffer },
160 { NULL, NULL, NULL }
164 main(int argc, char **argv)
166 unsigned x, x2;
167 int i;
168 int working = 1;
169 unsigned found[6];
170 (void) argc; (void) argv;
172 s = "squamous haberdasher gallimaufry";
174 memset(found, 0, sizeof(found));
176 for (i = 0; testcases[i].name; ++i) {
177 x = testcases[i].fill_fn();
178 found[i] = testcases[i].check_fn();
180 x2 = fill_a_buffer_nothing();
182 if (x != x2) {
183 working = 0;
187 if (!working || !found[0] || !found[1]) {
188 printf("It appears that this test case may not give you reliable "
189 "information. Sorry.\n");
192 if (!found[2] && !found[3]) {
193 printf("It appears that memset is good enough on this platform. Good.\n");
196 if (found[4] || found[5]) {
197 printf("ERROR: memwipe does not wipe data!\n");
198 return 1;
199 } else {
200 printf("OKAY: memwipe seems to work.");
201 return 0;