Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
lfittl committed Dec 30, 2023
1 parent 4ad8776 commit b07d671
Show file tree
Hide file tree
Showing 16 changed files with 189 additions and 372 deletions.
7 changes: 7 additions & 0 deletions scripts/extract_source.rb
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,13 @@ def write_out
# Other required functions
runner.deep_resolve('pg_printf')

# Required for Windows support
runner.deep_resolve('newNodeMacroHolder')
runner.deep_resolve('pg_leftmost_one_pos')
runner.deep_resolve('pg_number_of_ones')
runner.deep_resolve('strlcpy')
runner.deep_resolve('GetMessageEncoding')

runner.write_out

#puts runner.unresolved.inspect
Expand Down
9 changes: 9 additions & 0 deletions src/pg_query.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,20 @@
#include <utils/memutils.h>
#include <utils/memdebug.h>

#ifdef HAVE_PTHREAD
#include <pthread.h>
#endif

#include <signal.h>

const char* progname = "pg_query";

__thread sig_atomic_t pg_query_initialized = 0;

#ifdef HAVE_PTHREAD
static pthread_key_t pg_query_thread_exit_key;
static void pg_query_thread_exit(void *key);
#endif

void pg_query_init(void)
{
Expand All @@ -23,8 +28,10 @@ void pg_query_init(void)
MemoryContextInit();
SetDatabaseEncoding(PG_UTF8);

#ifdef HAVE_PTHREAD
pthread_key_create(&pg_query_thread_exit_key, pg_query_thread_exit);
pthread_setspecific(pg_query_thread_exit_key, TopMemoryContext);
#endif
}

void pg_query_free_top_memory_context(MemoryContext context)
Expand Down Expand Up @@ -55,11 +62,13 @@ void pg_query_free_top_memory_context(MemoryContext context)
ErrorContext = NULL;
}

#ifdef HAVE_PTHREAD
static void pg_query_thread_exit(void *key)
{
MemoryContext context = (MemoryContext) key;
pg_query_free_top_memory_context(context);
}
#endif

void pg_query_exit(void)
{
Expand Down
9 changes: 4 additions & 5 deletions src/pg_query_fingerprint.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// Ensure we have asprintf's definition on glibc-based platforms to avoid compiler warnings
#define _GNU_SOURCE
#include <stdio.h>

#include "pg_query.h"
Expand Down Expand Up @@ -369,12 +367,13 @@ PgQueryFingerprintResult pg_query_fingerprint_with_opts(const char* input, int p
_fingerprintFreeContext(&ctx);

XXH64_canonicalFromHash(&chash, result.fingerprint);
int err = asprintf(&result.fingerprint_str, "%02x%02x%02x%02x%02x%02x%02x%02x",
result.fingerprint_str = malloc(17 * sizeof(char));
int n = snprintf(result.fingerprint_str, 17, "%02x%02x%02x%02x%02x%02x%02x%02x",
chash.digest[0], chash.digest[1], chash.digest[2], chash.digest[3],
chash.digest[4], chash.digest[5], chash.digest[6], chash.digest[7]);
if (err == -1) {
if (n < 0 || n >= 17) {
PgQueryError* error = malloc(sizeof(PgQueryError));
error->message = strdup("Failed to output fingerprint string due to asprintf failure");
error->message = strdup("Failed to output fingerprint string due to snprintf failure");
result.error = error;
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/pg_query_parse.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ PgQueryProtobufParseResult pg_query_parse_protobuf_opts(const char* input, int p
{
MemoryContext ctx = NULL;
PgQueryInternalParsetreeAndError parsetree_and_error;
PgQueryProtobufParseResult result = {};
PgQueryProtobufParseResult result = {0};

ctx = pg_query_enter_memory_context();

Expand Down
9 changes: 6 additions & 3 deletions src/pg_query_parse_plpgsql.c
Original file line number Diff line number Diff line change
Expand Up @@ -486,14 +486,17 @@ PgQueryPlpgsqlParseResult pg_query_parse_plpgsql(const char* input)
if (func_and_error.func != NULL) {
char *func_json;
char *new_out;
size_t new_out_len;

func_json = plpgsqlToJSON(func_and_error.func);
plpgsql_free_function_memory(func_and_error.func);

int err = asprintf(&new_out, "%s%s,\n", result.plpgsql_funcs, func_json);
if (err == -1) {
new_out_len = strlen(result.plpgsql_funcs) + strlen(func_json) + 2;
new_out = malloc(new_out_len * sizeof(char));
int n = snprintf(new_out, new_out_len, "%s%s,\n", result.plpgsql_funcs, func_json);
if (n < 0 || n >= new_out_len) {
PgQueryError* error = malloc(sizeof(PgQueryError));
error->message = strdup("Failed to output PL/pgSQL functions due to asprintf failure");
error->message = strdup("Failed to output PL/pgSQL functions due to snprintf failure");
result.error = error;
} else {
free(result.plpgsql_funcs);
Expand Down
2 changes: 1 addition & 1 deletion src/pg_query_split.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ PgQuerySplitResult pg_query_split_with_parser(const char* input)
{
MemoryContext ctx = NULL;
PgQueryInternalParsetreeAndError parsetree_and_error;
PgQuerySplitResult result = {};
PgQuerySplitResult result = {0};

ctx = pg_query_enter_memory_context();

Expand Down
7 changes: 6 additions & 1 deletion src/postgres/include/pg_config.h
Original file line number Diff line number Diff line change
Expand Up @@ -650,7 +650,7 @@
#define PG_VERSION_NUM 160001

/* A string containing the version number, platform, and C compiler */
#define PG_VERSION_STR "PostgreSQL 16.1 on aarch64-apple-darwin21.6.0, compiled by Apple clang version 14.0.0 (clang-1400.0.29.102), 64-bit"
#define PG_VERSION_STR "PostgreSQL 16.1 on aarch64-apple-darwin22.3.0, compiled by Apple clang version 14.0.0 (clang-1400.0.29.202), 64-bit"

/* Define to 1 to allow profiling output to be saved separately for each
process. */
Expand Down Expand Up @@ -850,9 +850,14 @@
#undef HAVE_VISIBILITY_ATTRIBUTE
#undef HAVE__BUILTIN_CONSTANT_P
#undef HAVE__BUILTIN_TYPES_COMPATIBLE_P
#undef HAVE__BUILTIN_UNREACHABLE
#undef HAVE__BUILTIN_CLZ
#undef HAVE__BUILTIN_CTZ
#undef HAVE__BUILTIN_POPCOUNT
#undef HAVE_TYPEOF
#undef HAVE_GETOPT_H
#undef HAVE_SYSLOG
#undef HAVE_PTHREAD
#undef HAVE_PTHREAD_IS_THREADED_NP
#undef HAVE_STRERROR_R
#endif
208 changes: 1 addition & 207 deletions src/postgres/src_backend_postmaster_postmaster.c
Original file line number Diff line number Diff line change
Expand Up @@ -1001,214 +1001,8 @@ HANDLE PostmasterHandle;

#else /* WIN32 */

/*
* internal_forkexec win32 implementation
*
* - starts backend using CreateProcess(), in suspended state
* - writes out backend variables to the parameter file
* - during this, duplicates handles and sockets required for
* inheritance into the new process
* - resumes execution of the new process once the backend parameter
* file is complete.
*/
static pid_t
internal_forkexec(int argc, char *argv[], Port *port)
{
int retry_count = 0;
STARTUPINFO si;
PROCESS_INFORMATION pi;
int i;
int j;
char cmdLine[MAXPGPATH * 2];
HANDLE paramHandle;
BackendParameters *param;
SECURITY_ATTRIBUTES sa;
char paramHandleStr[32];
win32_deadchild_waitinfo *childinfo;

/* Make sure caller set up argv properly */
Assert(argc >= 3);
Assert(argv[argc] == NULL);
Assert(strncmp(argv[1], "--fork", 6) == 0);
Assert(argv[2] == NULL);

/* Resume here if we need to retry */
retry:

/* Set up shared memory for parameter passing */
ZeroMemory(&sa, sizeof(sa));
sa.nLength = sizeof(sa);
sa.bInheritHandle = TRUE;
paramHandle = CreateFileMapping(INVALID_HANDLE_VALUE,
&sa,
PAGE_READWRITE,
0,
sizeof(BackendParameters),
NULL);
if (paramHandle == INVALID_HANDLE_VALUE)
{
ereport(LOG,
(errmsg("could not create backend parameter file mapping: error code %lu",
GetLastError())));
return -1;
}

param = MapViewOfFile(paramHandle, FILE_MAP_WRITE, 0, 0, sizeof(BackendParameters));
if (!param)
{
ereport(LOG,
(errmsg("could not map backend parameter memory: error code %lu",
GetLastError())));
CloseHandle(paramHandle);
return -1;
}

/* Insert temp file name after --fork argument */
#ifdef _WIN64
sprintf(paramHandleStr, "%llu", (LONG_PTR) paramHandle);
#else
sprintf(paramHandleStr, "%lu", (DWORD) paramHandle);
#endif
argv[2] = paramHandleStr;

/* Format the cmd line */
cmdLine[sizeof(cmdLine) - 1] = '\0';
cmdLine[sizeof(cmdLine) - 2] = '\0';
snprintf(cmdLine, sizeof(cmdLine) - 1, "\"%s\"", postgres_exec_path);
i = 0;
while (argv[++i] != NULL)
{
j = strlen(cmdLine);
snprintf(cmdLine + j, sizeof(cmdLine) - 1 - j, " \"%s\"", argv[i]);
}
if (cmdLine[sizeof(cmdLine) - 2] != '\0')
{
ereport(LOG,
(errmsg("subprocess command line too long")));
UnmapViewOfFile(param);
CloseHandle(paramHandle);
return -1;
}

memset(&pi, 0, sizeof(pi));
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);

/*
* Create the subprocess in a suspended state. This will be resumed later,
* once we have written out the parameter file.
*/
if (!CreateProcess(NULL, cmdLine, NULL, NULL, TRUE, CREATE_SUSPENDED,
NULL, NULL, &si, &pi))
{
ereport(LOG,
(errmsg("CreateProcess() call failed: %m (error code %lu)",
GetLastError())));
UnmapViewOfFile(param);
CloseHandle(paramHandle);
return -1;
}

if (!save_backend_variables(param, port, pi.hProcess, pi.dwProcessId))
{
/*
* log made by save_backend_variables, but we have to clean up the
* mess with the half-started process
*/
if (!TerminateProcess(pi.hProcess, 255))
ereport(LOG,
(errmsg_internal("could not terminate unstarted process: error code %lu",
GetLastError())));
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
UnmapViewOfFile(param);
CloseHandle(paramHandle);
return -1; /* log made by save_backend_variables */
}

/* Drop the parameter shared memory that is now inherited to the backend */
if (!UnmapViewOfFile(param))
ereport(LOG,
(errmsg("could not unmap view of backend parameter file: error code %lu",
GetLastError())));
if (!CloseHandle(paramHandle))
ereport(LOG,
(errmsg("could not close handle to backend parameter file: error code %lu",
GetLastError())));

/*
* Reserve the memory region used by our main shared memory segment before
* we resume the child process. Normally this should succeed, but if ASLR
* is active then it might sometimes fail due to the stack or heap having
* gotten mapped into that range. In that case, just terminate the
* process and retry.
*/
if (!pgwin32_ReserveSharedMemoryRegion(pi.hProcess))
{
/* pgwin32_ReserveSharedMemoryRegion already made a log entry */
if (!TerminateProcess(pi.hProcess, 255))
ereport(LOG,
(errmsg_internal("could not terminate process that failed to reserve memory: error code %lu",
GetLastError())));
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
if (++retry_count < 100)
goto retry;
ereport(LOG,
(errmsg("giving up after too many tries to reserve shared memory"),
errhint("This might be caused by ASLR or antivirus software.")));
return -1;
}
// FIXME: How can we remove this code here always?

/*
* Now that the backend variables are written out, we start the child
* thread so it can start initializing while we set up the rest of the
* parent state.
*/
if (ResumeThread(pi.hThread) == -1)
{
if (!TerminateProcess(pi.hProcess, 255))
{
ereport(LOG,
(errmsg_internal("could not terminate unstartable process: error code %lu",
GetLastError())));
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return -1;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
ereport(LOG,
(errmsg_internal("could not resume thread of unstarted process: error code %lu",
GetLastError())));
return -1;
}

/*
* Queue a waiter to signal when this child dies. The wait will be handled
* automatically by an operating system thread pool. The memory will be
* freed by a later call to waitpid().
*/
childinfo = palloc(sizeof(win32_deadchild_waitinfo));
childinfo->procHandle = pi.hProcess;
childinfo->procId = pi.dwProcessId;

if (!RegisterWaitForSingleObject(&childinfo->waitHandle,
pi.hProcess,
pgwin32_deadchild_callback,
childinfo,
INFINITE,
WT_EXECUTEONLYONCE | WT_EXECUTEINWAITTHREAD))
ereport(FATAL,
(errmsg_internal("could not register process for wait: error code %lu",
GetLastError())));

/* Don't close pi.hProcess here - waitpid() needs access to it */

CloseHandle(pi.hThread);

return pi.dwProcessId;
}
#endif /* WIN32 */


Expand Down
Loading

0 comments on commit b07d671

Please sign in to comment.