PostgreSQL Source Code git master
test_cloexec.c File Reference
#include "postgres.h"
#include <fcntl.h>
#include <sys/stat.h>
#include "common/file_utils.h"
#include "port.h"
Include dependency graph for test_cloexec.c:

Go to the source code of this file.

Functions

static void run_parent_tests (const char *testfile1, const char *testfile2)
 
static void run_child_tests (const char *handle1_str, const char *handle2_str)
 
static bool try_write_to_handle (HANDLE h, const char *label)
 
int main (int argc, char *argv[])
 

Function Documentation

◆ main()

int main ( int  argc,
char *  argv[] 
)

Definition at line 32 of file test_cloexec.c.

33{
34 char testfile1[MAXPGPATH];
35 char testfile2[MAXPGPATH];
36
37 /* Windows-only test */
38#ifndef WIN32
39 fprintf(stderr, "This test only runs on Windows\n");
40 return 0;
41#endif
42
43 if (argc == 3)
44 {
45 /*
46 * Child mode: receives two handle values as hex strings and attempts
47 * to write to them.
48 */
49 run_child_tests(argv[1], argv[2]);
50 return 0;
51 }
52 else if (argc == 1)
53 {
54 /* Parent mode: opens files and spawns child */
55 snprintf(testfile1, sizeof(testfile1), "test_cloexec_1_%d.tmp", (int) getpid());
56 snprintf(testfile2, sizeof(testfile2), "test_cloexec_2_%d.tmp", (int) getpid());
57
58 run_parent_tests(testfile1, testfile2);
59
60 /* Clean up test files */
61 unlink(testfile1);
62 unlink(testfile2);
63
64 return 0;
65 }
66 else
67 {
68 fprintf(stderr, "Usage: %s [handle1_hex handle2_hex]\n", argv[0]);
69 return 1;
70 }
71}
#define fprintf(file, fmt, msg)
Definition: cubescan.l:21
#define MAXPGPATH
#define snprintf
Definition: port.h:260
static void run_child_tests(const char *handle1_str, const char *handle2_str)
Definition: test_cloexec.c:193
static void run_parent_tests(const char *testfile1, const char *testfile2)
Definition: test_cloexec.c:74

References fprintf, MAXPGPATH, run_child_tests(), run_parent_tests(), and snprintf.

◆ run_child_tests()

static void run_child_tests ( const char *  handle1_str,
const char *  handle2_str 
)
static

Definition at line 193 of file test_cloexec.c.

194{
195#ifdef WIN32
196 HANDLE h1,
197 h2;
198 bool h1_worked,
199 h2_worked;
200
201 /* Parse handle values from hex strings */
202 if (sscanf(handle1_str, "%p", &h1) != 1 ||
203 sscanf(handle2_str, "%p", &h2) != 1)
204 {
205 fprintf(stderr, "Child: Failed to parse handle values\n");
206 exit(1);
207 }
208
209 printf("Child: Received HANDLE1=%p (should fail - O_CLOEXEC)\n", h1);
210 printf("Child: Received HANDLE2=%p (should work - no O_CLOEXEC)\n", h2);
211
212 /* Try to write to both handles */
213 h1_worked = try_write_to_handle(h1, "HANDLE1");
214 h2_worked = try_write_to_handle(h2, "HANDLE2");
215
216 printf("Child: HANDLE1 (O_CLOEXEC): %s\n",
217 h1_worked ? "ACCESSIBLE (BAD!)" : "NOT ACCESSIBLE (GOOD!)");
218 printf("Child: HANDLE2 (no O_CLOEXEC): %s\n",
219 h2_worked ? "ACCESSIBLE (GOOD!)" : "NOT ACCESSIBLE (BAD!)");
220
221 /*
222 * For O_CLOEXEC to work correctly, h1 should NOT be accessible (h1_worked
223 * == false) and h2 SHOULD be accessible (h2_worked == true).
224 */
225 if (!h1_worked && h2_worked)
226 {
227 printf("Child: Test PASSED - O_CLOEXEC working correctly\n");
228 exit(0);
229 }
230 else
231 {
232 printf("Child: Test FAILED - O_CLOEXEC not working correctly\n");
233 exit(1);
234 }
235#endif
236}
#define printf(...)
Definition: port.h:266
static bool try_write_to_handle(HANDLE h, const char *label)
Definition: test_cloexec.c:239

References fprintf, printf, and try_write_to_handle().

Referenced by main().

◆ run_parent_tests()

static void run_parent_tests ( const char *  testfile1,
const char *  testfile2 
)
static

Definition at line 74 of file test_cloexec.c.

75{
76#ifdef WIN32
77 int fd1,
78 fd2;
79 HANDLE h1,
80 h2;
81 char cmdline[1024];
82 STARTUPINFO si;
83 PROCESS_INFORMATION pi;
84 DWORD exit_code;
85
86 printf("Parent: Opening test files...\n");
87
88 /*
89 * Open first file WITH O_CLOEXEC - should NOT be inherited
90 */
91 fd1 = open(testfile1, O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC, 0600);
92 if (fd1 < 0)
93 {
94 fprintf(stderr, "Failed to open %s: %s\n", testfile1, strerror(errno));
95 exit(1);
96 }
97
98 /*
99 * Open second file WITHOUT O_CLOEXEC - should be inherited
100 */
101 fd2 = open(testfile2, O_RDWR | O_CREAT | O_TRUNC, 0600);
102 if (fd2 < 0)
103 {
104 fprintf(stderr, "Failed to open %s: %s\n", testfile2, strerror(errno));
105 close(fd1);
106 exit(1);
107 }
108
109 /* Get Windows HANDLEs from file descriptors */
110 h1 = (HANDLE) _get_osfhandle(fd1);
111 h2 = (HANDLE) _get_osfhandle(fd2);
112
113 if (h1 == INVALID_HANDLE_VALUE || h2 == INVALID_HANDLE_VALUE)
114 {
115 fprintf(stderr, "Failed to get OS handles\n");
116 close(fd1);
117 close(fd2);
118 exit(1);
119 }
120
121 printf("Parent: fd1=%d (O_CLOEXEC) -> HANDLE=%p\n", fd1, h1);
122 printf("Parent: fd2=%d (no O_CLOEXEC) -> HANDLE=%p\n", fd2, h2);
123
124 /*
125 * Spawn child process with bInheritHandles=TRUE, passing handle values as
126 * hex strings
127 */
128 snprintf(cmdline, sizeof(cmdline), "\"%s\" %p %p",
129 GetCommandLine(), h1, h2);
130
131 /*
132 * Find the actual executable path by removing any arguments from
133 * GetCommandLine().
134 */
135 {
136 char exe_path[MAX_PATH];
137 char *space_pos;
138
139 GetModuleFileName(NULL, exe_path, sizeof(exe_path));
140 snprintf(cmdline, sizeof(cmdline), "\"%s\" %p %p",
141 exe_path, h1, h2);
142 }
143
144 memset(&si, 0, sizeof(si));
145 si.cb = sizeof(si);
146 memset(&pi, 0, sizeof(pi));
147
148 printf("Parent: Spawning child process...\n");
149 printf("Parent: Command line: %s\n", cmdline);
150
151 if (!CreateProcess(NULL, /* application name */
152 cmdline, /* command line */
153 NULL, /* process security attributes */
154 NULL, /* thread security attributes */
155 TRUE, /* bInheritHandles - CRITICAL! */
156 0, /* creation flags */
157 NULL, /* environment */
158 NULL, /* current directory */
159 &si, /* startup info */
160 &pi)) /* process information */
161 {
162 fprintf(stderr, "CreateProcess failed: %lu\n", GetLastError());
163 close(fd1);
164 close(fd2);
165 exit(1);
166 }
167
168 printf("Parent: Waiting for child process...\n");
169
170 /* Wait for child to complete */
171 WaitForSingleObject(pi.hProcess, INFINITE);
172 GetExitCodeProcess(pi.hProcess, &exit_code);
173
174 CloseHandle(pi.hProcess);
175 CloseHandle(pi.hThread);
176
177 close(fd1);
178 close(fd2);
179
180 printf("Parent: Child exit code: %lu\n", exit_code);
181
182 if (exit_code == 0)
183 printf("Parent: SUCCESS - O_CLOEXEC behavior verified\n");
184 else
185 {
186 printf("Parent: FAILURE - O_CLOEXEC not working correctly\n");
187 exit(1);
188 }
189#endif
190}
#define close(a)
Definition: win32.h:12
#define strerror
Definition: port.h:273
#define O_CLOEXEC
Definition: win32_port.h:344

References close, fprintf, O_CLOEXEC, printf, snprintf, and strerror.

Referenced by main().

◆ try_write_to_handle()

static bool try_write_to_handle ( HANDLE  h,
const char *  label 
)
static

Definition at line 239 of file test_cloexec.c.

240{
241#ifdef WIN32
242 const char *test_data = "test\n";
243 DWORD bytes_written;
244 BOOL result;
245
246 result = WriteFile(h, test_data, strlen(test_data), &bytes_written, NULL);
247
248 if (result && bytes_written == strlen(test_data))
249 {
250 printf("Child: Successfully wrote to %s\n", label);
251 return true;
252 }
253 else
254 {
255 printf("Child: Failed to write to %s (error %lu)\n",
256 label, GetLastError());
257 return false;
258 }
259#else
260 return false;
261#endif
262}
static char * label

References label, and printf.

Referenced by run_child_tests().