1/*
2 * Copyright (c) 2003-2006 Apple Computer, Inc. All Rights Reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. Please obtain a copy of the License at
10 * http://www.opensource.apple.com/apsl/ and read it before using this
11 * file.
12 *
13 * The Original Code and all software distributed under the License are
14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
18 * Please see the License for the specific language governing rights and
19 * limitations under the License.
20 *
21 * @APPLE_LICENSE_HEADER_END@
22 *
23 * testleaks.c
24 */
25
26#include <errno.h>
27#include <stdio.h>
28#include <stdlib.h>
29#include <string.h>
30#include <sys/wait.h>
31#include <unistd.h>
32
33#include "testleaks.h"
34#include "testmore.h"
35
36#if 0
37static char *cf_user_text_encoding_var;
38#endif
39
40int
41test_leaks(void)
42{
43	return 0;
44#if 0
45	int leaks = 0;
46	pid_t child;
47	pid_t parent;
48
49	setup("leaks");
50
51	/* Work around the fact that CF calls setenv, which leaks. */
52	cf_user_text_encoding_var = getenv("__CF_USER_TEXT_ENCODING");
53
54	ok_unix(parent = getpid(), "getpid");
55	int cld_stdout[2] = {};
56	ok_unix(child = pipe(cld_stdout), "pipe");
57	ok_unix(child = fork(), "fork");
58	switch (child)
59	{
60	case -1:
61		break;
62	case 0:
63	{
64		/* child. */
65
66		/* Set childs stdout and stderr to pipe. */
67		ok_unix(close(cld_stdout[0]), "close parent end of pipe");
68		ok_unix(dup2(cld_stdout[1], 1), "reopen stdout on pipe");
69#if 0
70		ok_unix(dup2(cld_stdout[1], 2), "reopen stderr on pipe");
71#endif
72
73		int argc = 0;
74		char *const *argv = NULL;
75		char **argvec = (char **)malloc((argc + 2) * sizeof(char *));
76		char pidstr[8];
77		int ix;
78
79		sprintf(pidstr, "%d", parent);
80		argvec[0] = "/usr/bin/leaks";
81		for (ix = 1; ix < argc; ++ix)
82			argvec[ix] = argv[ix];
83		argvec[ix] = pidstr;
84		argvec[ix + 1] = NULL;
85
86		ok_unix(execv(argvec[0], argvec), "execv");
87		_exit(1);
88		break;
89	}
90	default:
91	{
92		/* Parent. */
93		ok_unix(close(cld_stdout[1]), "close child end of pipe");
94
95		/* Set statemachine initial state to 0. */
96		int state = 0;
97		/* True iff the last char read was a newline. */
98		int newline = 1;
99		char buf[4098];
100		for (;;)
101		{
102			char *p = buf + 2;
103			ssize_t bytes_read;
104			bytes_read = read(cld_stdout[0], p, 4096);
105			if (bytes_read <= 0)
106				break;
107
108			int start = newline ? -2 : 0;
109			int ix = 0;
110			for (ix = 0; ix < bytes_read; ++ix)
111			{
112				/* Simple state machine for parsing leaks output.
113				 * Looks for
114				 *     '[^\n]*\n[^:]*: ([0-9]*)'
115				 * and sets leaks to atoi of the ([0-9]*) bit. */
116				switch (state)
117				{
118				case 0: if (p[ix] == '\n') state = 1; break;
119				case 1: if (p[ix] == ':') state = 2; break;
120				case 2: if (p[ix] == ' ') state = 3; break;
121				case 3:
122					if (p[ix] <= '0' || p[ix] >='9')
123						state = 4;
124					else
125						leaks = leaks * 10 + p[ix] - '0';
126					break;
127				case 4: break;
128				}
129
130				/* If there is a newline in the input or we are looking
131				   at the last char of the buffer it's time to write the
132				   output. */
133				if (p[ix] == '\n' || ix + 1 >= bytes_read)
134				{
135					/* If the previous char was a newline we prefix the
136					   output with "# ". */
137					if (newline)
138					{
139						p[start] = '#';
140						p[start + 1] = ' ';
141					}
142					fwrite(p + start, ix + 1 - start, 1, stdout);
143					if (p[ix] == '\n')
144					{
145						start = ix - 1;
146						newline = 1;
147					}
148					else
149						newline = 0;
150				}
151			}
152		}
153
154		int status = 0;
155		for (;;)
156		{
157			/* Wait for the child to exit. */
158			pid_t waited_pid = waitpid(child, &status, 0);
159			if (waited_pid == -1)
160			{
161				int error = errno;
162				/* Keep going if we get interupted but bail out on any
163				   other error. */
164				if (error == EINTR)
165					continue;
166
167				ok_unix(waited_pid, "waitpid");
168				break;
169			}
170
171			if (WIFEXITED(status))
172			{
173				is(WEXITSTATUS(status), 0, "leaks exit status");
174				break;
175			}
176			else if (WIFSIGNALED(status))
177			{
178				is(WTERMSIG(status), 0, "leaks terminated by");
179				break;
180			}
181		}
182		break;
183	}
184	}
185
186	return leaks;
187#endif
188}
189