1/*
2 *
3 *   Copyright (c) International Business Machines  Corp., 2002
4 *   Copyright (c) 2012 Cyril Hrubis <chrubis@suse.cz>
5 *
6 *   This program is free software;  you can redistribute it and/or modify
7 *   it under the terms of the GNU General Public License as published by
8 *   the Free Software Foundation; either version 2 of the License, or
9 *   (at your option) any later version.
10 *
11 *   This program 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
14 *   the GNU General Public License for more details.
15 *
16 *   You should have received a copy of the GNU General Public License
17 *   along with this program;  if not, write to the Free Software
18 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/* IBM Corporation */
22/* 06/30/2001	Port to Linux	nsharoff@us.ibm.com */
23/* 10/30/2002	Port to LTP	dbarrera@us.ibm.com */
24
25/*======================================================================
26/	=================== TESTPLAN SEGMENT ===================
27>KEYS:	< calloc, malloc, free, realloc, valloc
28>WHAT:	< check that memory can be allocated and freed. check for zeroed
29   	< memory.
30>HOW:	< Allocate a big chunk of memory, verify it is available (zeroed
31	< in the case of calloc).
32	< Write into it and verify, free memory and verify free was
33	< successful.
34	< In the case of valloc, allocate memory and free it (do this for
35	< several iterations). Check if valloc returns unaligned pointers.
36	< If valloc causes a SIGSEGV, that means a failure has occured.
37>BUGS:	<
38======================================================================*/
39
40#include <stdio.h>
41#include <signal.h>
42#include <stdlib.h>
43#include "test.h"
44#include <unistd.h>
45#include <errno.h>
46#include <time.h>
47#include <string.h>
48#include <sys/types.h>
49#include <sys/user.h>
50
51#define MEMSIZE	8192*8192
52
53void on_mem_fault(int sig);
54
55char *TCID = "mem02";
56int TST_TOTAL = 1;
57
58static void usage(char *progname)
59{
60	fprintf(stderr, "usage: %s -m memsize\n", progname);
61	fprintf(stderr, "\t-m specify the size of memory to allocate, in MB\n");
62	exit(1);
63}
64
65int main(int argc, char **argv)
66{
67	int i;
68	char *pm1, *pm2, *pm3, *pm4;
69	long pm6;
70	void *memptr;
71	long laddr;
72	int iteration_count;
73	int size;		/* Size to memory to be valloced */
74	int pagesize = 12;	/* 2^12 = 4096, PAGESIZE      */
75	int memsize = MEMSIZE;	/* Size of memory to allocate */
76	extern char *optarg;	/* getopt() function global variables */
77	extern int optopt;	/* stores bad option passed to the program */
78	int ch;
79
80	optarg = NULL;
81	opterr = 0;
82
83	while ((ch = getopt(argc, argv, "m:")) != -1) {
84		switch (ch) {
85		case 'm':
86			if (optarg)
87				memsize = atoi(optarg) * 1024 * 1024;
88			else
89				fprintf(stderr, "%s: option -%c requires "
90					"an argument\n", argv[0], optopt);
91			break;
92		default:
93			usage(argv[0]);
94			exit(1);
95		}
96	}
97
98	/* check out calloc/free */
99	if ((pm2 = pm1 = calloc(memsize, 1)) == NULL) {
100
101		tst_brkm(TFAIL, NULL, "calloc - alloc of %dMB failed",
102			 memsize / 1024 / 1024);
103	}
104
105	for (i = 0; i < memsize; i++)
106		if (*pm2++ != 0) {
107			tst_brkm(TFAIL, NULL,
108				 "calloc returned non zero memory");
109		}
110
111	pm2 = pm1;
112	for (i = 0; i < memsize; i++)
113		*pm2++ = 'X';
114	pm2 = pm1;
115	for (i = 0; i < memsize; i++)
116		if (*pm2++ != 'X') {
117			tst_brkm(TFAIL, NULL,
118				 "could not write/verify memory ");
119		}
120
121	free(pm1);
122
123	tst_resm(TPASS, "calloc - calloc of %uMB of memory succeeded",
124		 memsize / 1024 / 1024);
125
126/*--------------------------------------------------------------------*/
127
128	/* check out malloc/free */
129	if ((pm2 = pm1 = malloc(memsize)) == NULL) {
130		tst_brkm(TFAIL, NULL, "malloc did not alloc memory ");
131	}
132
133	for (i = 0; i < memsize; i++)
134		*pm2++ = 'X';
135	pm2 = pm1;
136	for (i = 0; i < memsize; i++)
137		if (*pm2++ != 'X') {
138			tst_brkm(TFAIL, NULL,
139				 "could not write/verify memory ");
140		}
141
142	free(pm1);
143
144	tst_resm(TPASS, "malloc - malloc of %uMB of memory succeeded",
145		 memsize / 1024 / 1024);
146
147/*--------------------------------------------------------------------*/
148
149	/* check out realloc */
150
151	pm4 = pm3 = malloc(10);
152	for (i = 0; i < 10; i++)
153		*pm4++ = 'X';
154
155	/* realloc with reduced size */
156	pm4 = realloc(pm3, 5);
157	pm6 = (long)pm4;
158	pm3 = pm4;
159	/* verify contents did not change */
160	for (i = 0; i < 5; i++) {
161		if (*pm4++ != 'X') {
162			tst_brkm(TFAIL, NULL,
163				 "realloc changed memory contents");
164		}
165	}
166
167	tst_resm(TPASS, "realloc - realloc of 5 bytes succeeded");
168
169	/* realloc with increased size after fragmenting memory */
170	pm4 = realloc(pm3, 15);
171	pm6 = (long)pm3;
172	pm3 = pm4;
173	/* verify contents did not change */
174	for (i = 0; i < 5; i++) {
175		if (*pm3++ != 'X') {
176			tst_brkm(TFAIL, NULL,
177				 "realloc changed memory contents");
178		}
179	}
180
181	tst_resm(TPASS, "realloc - realloc of 15 bytes succeeded");
182	free(pm4);
183
184/*--------------------------------------------------------------------*/
185	/*
186	 * Check out for valloc failures
187	 */
188
189	/*
190	 * Setup to catch the memory fault, otherwise the core might
191	 * be dumped on failures.
192	 */
193	if ((signal(SIGSEGV, on_mem_fault)) == SIG_ERR) {
194		tst_brkm(TFAIL, NULL,
195			 "Could not get signal handler for SIGSEGV");
196	}
197
198	srand(1);		/* Ensure Determinism         */
199
200	for (iteration_count = 15000; iteration_count > 0; iteration_count--) {
201		/*
202		 * size is a fraction of 100000 and is determined by rand().
203		 */
204		size = (int)((rand() / (float)RAND_MAX) * 100000) + 1;
205		memptr = valloc(size);
206
207		/*
208		 * Check to see if valloc returns unaligned data.
209		 * This can be done by copying the memory address into
210		 * a variable and the by diving and multipying the address
211		 * by the pagesize and checking.
212		 */
213		laddr = (long)memptr;
214		if (((laddr >> pagesize) << pagesize) != laddr) {
215			tst_brkm(TFAIL, NULL,
216				 "Valloc returned unaligned data");
217		}
218
219		free(memptr);
220	}
221
222	tst_exit();
223}
224
225/*
226 * void
227 * on_mem_fault(int sig)
228 *
229 *	on_mem_fault() is a signal handler used by the valloc test-case
230 *	(block 3). This function will catch the signal, indicate a failure,
231 *	write to the log file (a failure message) and exit the test.
232 */
233void on_mem_fault(int sig)
234{
235	tst_brkm(TFAIL, NULL, "\tTest failed on receipt of a SIGSEGV signal");
236}
237