tests: Add HAVE_MMAP check for MinGW.
[libgcrypt.git] / tests / t-secmem.c
1 /* t-secmem.c - Test the secmem memory allocator
2  * Copyright (C) 2016 g10 Code GmbH
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser General Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this program; if not, see <http://www.gnu.org/licenses/>.
18  */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif
23 #include <stdarg.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <unistd.h>
29
30 #define PGM "t-secmem"
31
32 #include "t-common.h"
33 #include "../src/gcrypt-testapi.h"
34
35
36 #define DEFAULT_PAGE_SIZE 4096
37 #define MINIMUM_POOL_SIZE 16384
38 static size_t pool_size;
39 static size_t chunk_size;
40
41 static void
42 test_secmem (void)
43 {
44   void *a[28];
45   void *b;
46   int i;
47
48   memset (a, 0, sizeof a);
49
50   /* Allocating 28*512=14k should work in the default 16k pool even
51    * with extra alignment requirements.  */
52   for (i=0; i < DIM(a); i++)
53     a[i] = gcry_xmalloc_secure (chunk_size);
54
55   /* Allocating another 2k should fail for the default 16k pool.  */
56   b = gcry_malloc_secure (chunk_size*4);
57   if (b)
58     fail ("allocation did not fail as expected\n");
59
60   for (i=0; i < DIM(a); i++)
61     xfree (a[i]);
62   xfree (b);
63 }
64
65
66 static void
67 test_secmem_overflow (void)
68 {
69   void *a[150];
70   int i;
71
72   memset (a, 0, sizeof a);
73
74   /* Allocating 150*512=75k should require more than one overflow buffer.  */
75   for (i=0; i < DIM(a); i++)
76     {
77       a[i] = gcry_xmalloc_secure (chunk_size);
78       if (verbose && !(i %40))
79         xgcry_control (GCRYCTL_DUMP_SECMEM_STATS, 0 , 0);
80     }
81
82   if (debug)
83     xgcry_control (PRIV_CTL_DUMP_SECMEM_STATS, 0 , 0);
84   if (verbose)
85     xgcry_control (GCRYCTL_DUMP_SECMEM_STATS, 0 , 0);
86   for (i=0; i < DIM(a); i++)
87     xfree (a[i]);
88 }
89
90
91 /* This function is called when we ran out of core and there is no way
92  * to return that error to the caller (xmalloc or mpi allocation).  */
93 static int
94 outofcore_handler (void *opaque, size_t req_n, unsigned int flags)
95 {
96   static int been_here;  /* Used to protect against recursive calls. */
97
98   (void)opaque;
99
100   /* Protect against a second call.  */
101   if (been_here)
102     return 0; /* Let libgcrypt call its own fatal error handler.  */
103   been_here = 1;
104
105   info ("outofcore handler invoked");
106   xgcry_control (PRIV_CTL_DUMP_SECMEM_STATS, 0 , 0);
107   fail ("out of core%s while allocating %lu bytes",
108        (flags & 1)?" in secure memory":"", (unsigned long)req_n);
109
110   die ("stopped");
111   /*NOTREACHED*/
112   return 0;
113 }
114
115
116 int
117 main (int argc, char **argv)
118 {
119   int last_argc = -1;
120   long int pgsize_val = -1;
121   size_t pgsize;
122
123 #if HAVE_MMAP
124 # if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
125   pgsize_val = sysconf (_SC_PAGESIZE);
126 # elif defined(HAVE_GETPAGESIZE)
127   pgsize_val = getpagesize ();
128 # endif
129 #endif
130   pgsize = (pgsize_val > 0)? pgsize_val : DEFAULT_PAGE_SIZE;
131
132   pool_size = (MINIMUM_POOL_SIZE + pgsize - 1) & ~(pgsize - 1);
133   chunk_size = pool_size / 32;
134
135   if (argc)
136     { argc--; argv++; }
137
138   while (argc && last_argc != argc )
139     {
140       last_argc = argc;
141       if (!strcmp (*argv, "--"))
142         {
143           argc--; argv++;
144           break;
145         }
146       else if (!strcmp (*argv, "--help"))
147         {
148           fputs ("usage: " PGM " [options]\n"
149                  "Options:\n"
150                  "  --verbose       print timings etc.\n"
151                  "  --debug         flyswatter\n"
152                  , stdout);
153           exit (0);
154         }
155       else if (!strcmp (*argv, "--verbose"))
156         {
157           verbose++;
158           argc--; argv++;
159         }
160       else if (!strcmp (*argv, "--debug"))
161         {
162           verbose += 2;
163           debug++;
164           argc--; argv++;
165         }
166       else if (!strncmp (*argv, "--", 2))
167         die ("unknown option '%s'", *argv);
168     }
169
170   if (!gcry_check_version (GCRYPT_VERSION))
171     die ("version mismatch; pgm=%s, library=%s\n",
172          GCRYPT_VERSION, gcry_check_version (NULL));
173   if (debug)
174     xgcry_control (GCRYCTL_SET_DEBUG_FLAGS, 1u , 0);
175   xgcry_control (GCRYCTL_ENABLE_QUICK_RANDOM, 0);
176   xgcry_control (GCRYCTL_INIT_SECMEM, pool_size, 0);
177   gcry_set_outofcore_handler (outofcore_handler, NULL);
178   xgcry_control (GCRYCTL_INITIALIZATION_FINISHED, 0);
179
180   /* Libgcrypt prints a warning when the first overflow is allocated;
181    * we do not want to see that.  */
182   if (!verbose)
183     xgcry_control (GCRYCTL_DISABLE_SECMEM_WARN, 0);
184
185
186   test_secmem ();
187   test_secmem_overflow ();
188   /* FIXME: We need to improve the tests, for example by registering
189    * our own log handler and comparing the output of
190    * PRIV_CTL_DUMP_SECMEM_STATS to expected pattern.  */
191
192   if (verbose)
193     {
194       xgcry_control (PRIV_CTL_DUMP_SECMEM_STATS, 0 , 0);
195       xgcry_control (GCRYCTL_DUMP_SECMEM_STATS, 0 , 0);
196     }
197
198   info ("All tests completed.  Errors: %d\n", error_count);
199   xgcry_control (GCRYCTL_TERM_SECMEM, 0 , 0);
200   return !!error_count;
201 }