PostgreSQL Source Code git master
Loading...
Searching...
No Matches
test_cloexec.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * test_cloexec.c
4 * Test O_CLOEXEC flag handling on Windows
5 *
6 * This program tests that:
7 * 1. File handles opened with O_CLOEXEC are NOT inherited by child processes
8 * 2. File handles opened without O_CLOEXEC ARE inherited by child processes
9 *
10 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
11 *
12 *-------------------------------------------------------------------------
13 */
14
15#include "postgres.h"
16
17#include <fcntl.h>
18#include <sys/stat.h>
19
20#ifdef WIN32
21#include <windows.h>
22#endif
23
24#include "common/file_utils.h"
25#include "port.h"
26
27#ifdef WIN32
28static void run_parent_tests(const char *testfile1, const char *testfile2);
29static void run_child_tests(const char *handle1_str, const char *handle2_str);
30static bool try_write_to_handle(HANDLE h, const char *label);
31#endif
32
33int
34main(int argc, char *argv[])
35{
36 /* Windows-only test */
37#ifndef WIN32
38 fprintf(stderr, "This test only runs on Windows\n");
39 return 0;
40#else
41 char testfile1[MAXPGPATH];
42 char testfile2[MAXPGPATH];
43
44 if (argc == 3)
45 {
46 /*
47 * Child mode: receives two handle values as hex strings and attempts
48 * to write to them.
49 */
50 run_child_tests(argv[1], argv[2]);
51 return 0;
52 }
53 else if (argc == 1)
54 {
55 /* Parent mode: opens files and spawns child */
56 snprintf(testfile1, sizeof(testfile1), "test_cloexec_1_%d.tmp", (int) getpid());
57 snprintf(testfile2, sizeof(testfile2), "test_cloexec_2_%d.tmp", (int) getpid());
58
60
61 /* Clean up test files */
64
65 return 0;
66 }
67 else
68 {
69 fprintf(stderr, "Usage: %s [handle1_hex handle2_hex]\n", argv[0]);
70 return 1;
71 }
72#endif
73}
74
75#ifdef WIN32
76static void
77run_parent_tests(const char *testfile1, const char *testfile2)
78{
79 int fd1,
80 fd2;
81 HANDLE h1,
82 h2;
83 char exe_path[MAXPGPATH];
84 char cmdline[MAXPGPATH + 100];
85 STARTUPINFO si = {.cb = sizeof(si)};
88
89 printf("Parent: Opening test files...\n");
90
91 /* Open first file WITH O_CLOEXEC - should NOT be inherited */
93 if (fd1 < 0)
94 {
95 fprintf(stderr, "Failed to open %s: %s\n", testfile1, strerror(errno));
96 exit(1);
97 }
98
99 /* Open second file WITHOUT O_CLOEXEC - should be inherited */
100 fd2 = open(testfile2, O_RDWR | O_CREAT | O_TRUNC, 0600);
101 if (fd2 < 0)
102 {
103 fprintf(stderr, "Failed to open %s: %s\n", testfile2, strerror(errno));
104 close(fd1);
105 exit(1);
106 }
107
108 /* Get Windows HANDLEs from file descriptors */
111
113 {
114 fprintf(stderr, "Failed to get OS handles\n");
115 close(fd1);
116 close(fd2);
117 exit(1);
118 }
119
120 printf("Parent: fd1=%d (O_CLOEXEC) -> HANDLE=%p\n", fd1, h1);
121 printf("Parent: fd2=%d (no O_CLOEXEC) -> HANDLE=%p\n", fd2, h2);
122
123 /*
124 * Find the actual executable path by removing any arguments from
125 * GetCommandLine(), and add our new arguments.
126 */
128 snprintf(cmdline, sizeof(cmdline), "\"%s\" %p %p", exe_path, h1, h2);
129
130 printf("Parent: Spawning child process...\n");
131 printf("Parent: Command line: %s\n", cmdline);
132
133 if (!CreateProcess(NULL, /* application name */
134 cmdline, /* command line */
135 NULL, /* process security attributes */
136 NULL, /* thread security attributes */
137 TRUE, /* bInheritHandles - CRITICAL! */
138 0, /* creation flags */
139 NULL, /* environment */
140 NULL, /* current directory */
141 &si, /* startup info */
142 &pi)) /* process information */
143 {
144 fprintf(stderr, "CreateProcess failed: %lu\n", GetLastError());
145 close(fd1);
146 close(fd2);
147 exit(1);
148 }
149
150 printf("Parent: Waiting for child process...\n");
151
152 /* Wait for child to complete */
154 GetExitCodeProcess(pi.hProcess, &exit_code);
155
156 CloseHandle(pi.hProcess);
157 CloseHandle(pi.hThread);
158
159 close(fd1);
160 close(fd2);
161
162 printf("Parent: Child exit code: %lu\n", exit_code);
163
164 if (exit_code == 0)
165 {
166 printf("Parent: SUCCESS - O_CLOEXEC behavior verified\n");
167 }
168 else
169 {
170 printf("Parent: FAILURE - O_CLOEXEC not working correctly\n");
171 exit(1);
172 }
173}
174
175static void
176run_child_tests(const char *handle1_str, const char *handle2_str)
177{
178 HANDLE h1,
179 h2;
180 bool h1_worked,
181 h2_worked;
182
183 /* Parse handle values from hex strings */
184 if (sscanf(handle1_str, "%p", &h1) != 1 ||
185 sscanf(handle2_str, "%p", &h2) != 1)
186 {
187 fprintf(stderr, "Child: Failed to parse handle values\n");
188 exit(1);
189 }
190
191 printf("Child: Received HANDLE1=%p (should fail - O_CLOEXEC)\n", h1);
192 printf("Child: Received HANDLE2=%p (should work - no O_CLOEXEC)\n", h2);
193
194 /* Try to write to both handles */
195 h1_worked = try_write_to_handle(h1, "HANDLE1");
196 h2_worked = try_write_to_handle(h2, "HANDLE2");
197
198 printf("Child: HANDLE1 (O_CLOEXEC): %s\n",
199 h1_worked ? "ACCESSIBLE (BAD!)" : "NOT ACCESSIBLE (GOOD!)");
200 printf("Child: HANDLE2 (no O_CLOEXEC): %s\n",
201 h2_worked ? "ACCESSIBLE (GOOD!)" : "NOT ACCESSIBLE (BAD!)");
202
203 /*
204 * For O_CLOEXEC to work correctly, h1 should NOT be accessible (h1_worked
205 * == false) and h2 SHOULD be accessible (h2_worked == true).
206 */
207 if (!h1_worked && h2_worked)
208 {
209 printf("Child: Test PASSED - O_CLOEXEC working correctly\n");
210 exit(0);
211 }
212 else
213 {
214 printf("Child: Test FAILED - O_CLOEXEC not working correctly\n");
215 exit(1);
216 }
217}
218
219static bool
220try_write_to_handle(HANDLE h, const char *label)
221{
222 const char *test_data = "test\n";
224 BOOL result;
225
227
228 if (result && bytes_written == strlen(test_data))
229 {
230 printf("Child: Successfully wrote to %s\n", label);
231 return true;
232 }
233 else
234 {
235 printf("Child: Failed to write to %s (error %lu)\n",
237 return false;
238 }
239}
240#endif
int main(void)
#define fprintf(file, fmt, msg)
Definition cubescan.l:21
#define close(a)
Definition win32.h:12
static char * label
#define MAXPGPATH
#define strerror
Definition port.h:273
#define snprintf
Definition port.h:260
#define printf(...)
Definition port.h:266
static int fb(int x)
#define O_CLOEXEC
Definition win32_port.h:344