From e67347944910653edafc7b00e51c298e50a37a00 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Sat, 14 Sep 2024 11:02:21 -0700
Subject: [PATCH] Removed SDL_WriteProcess()
This had the unfortunate side-effect of blocking if you tried to write too much. Instead you can use SDL_GetProcessInput() and handle SDL_IO_STATUS_NOT_READY as needed.
Fixes https://github.com/libsdl-org/SDL/issues/10834
---
include/SDL3/SDL_process.h | 81 +++++++++----------------------
src/dynapi/SDL_dynapi.sym | 5 +-
src/dynapi/SDL_dynapi_overrides.h | 5 +-
src/dynapi/SDL_dynapi_procs.h | 5 +-
src/process/SDL_process.c | 57 +++-------------------
test/testprocess.c | 39 ++++++++-------
6 files changed, 58 insertions(+), 134 deletions(-)
diff --git a/include/SDL3/SDL_process.h b/include/SDL3/SDL_process.h
index 17b727c5405a8..c7696a10df2ba 100644
--- a/include/SDL3/SDL_process.h
+++ b/include/SDL3/SDL_process.h
@@ -28,7 +28,7 @@
* processes.
*
* You can create a new subprocess with SDL_CreateProcess() and optionally
- * read and write to it using SDL_ReadProcess() and SDL_WriteProcess(). If
+ * read and write to it using SDL_ReadProcess() or SDL_GetProcessInput() and SDL_GetProcessOutput(). If
* more advanced functionality like chaining input between processes is
* necessary, you can use SDL_CreateProcessWithProperties().
*
@@ -66,7 +66,7 @@ typedef struct SDL_Process SDL_Process;
* Setting pipe_stdio to SDL_TRUE is equivalent to setting
* `SDL_PROP_PROCESS_CREATE_STDIN_NUMBER` and
* `SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER` to `SDL_PROCESS_STDIO_APP`, and
- * will allow the use of SDL_ReadProcess() and SDL_WriteProcess().
+ * will allow the use of SDL_ReadProcess() or SDL_GetProcessInput() and SDL_GetProcessOutput().
*
* See SDL_CreateProcessWithProperties() for more details.
*
@@ -85,7 +85,8 @@ typedef struct SDL_Process SDL_Process;
* \sa SDL_CreateProcessWithProperties
* \sa SDL_GetProcessProperties
* \sa SDL_ReadProcess
- * \sa SDL_WriteProcess
+ * \sa SDL_GetProcessInput
+ * \sa SDL_GetProcessOutput
* \sa SDL_KillProcess
* \sa SDL_WaitProcess
* \sa SDL_DestroyProcess
@@ -107,8 +108,8 @@ extern SDL_DECLSPEC SDL_Process *SDLCALL SDL_CreateProcess(const char * const *a
* If a standard I/O stream is set to SDL_PROCESS_STDIO_APP, it is connected
* to a new SDL_IOStream that is available to the application. Standard input
* will be available as `SDL_PROP_PROCESS_STDIN_POINTER` and allows
- * SDL_WriteProcess(), standard output will be available as
- * `SDL_PROP_PROCESS_STDOUT_POINTER` and allows SDL_ReadProcess(), and
+ * SDL_GetProcessInput(), standard output will be available as
+ * `SDL_PROP_PROCESS_STDOUT_POINTER` and allows SDL_ReadProcess() and SDL_GetProcessOutput(), and
* standard error will be available as `SDL_PROP_PROCESS_STDERR_POINTER` in
* the properties for the created process.
*
@@ -130,7 +131,8 @@ extern SDL_DECLSPEC SDL_Process *SDLCALL SDL_CreateProcess(const char * const *a
* \sa SDL_CreateProcessWithProperties
* \sa SDL_GetProcessProperties
* \sa SDL_ReadProcess
- * \sa SDL_WriteProcess
+ * \sa SDL_GetProcessInput
+ * \sa SDL_GetProcessOutput
*/
typedef enum SDL_ProcessIO
{
@@ -193,7 +195,8 @@ typedef enum SDL_ProcessIO
* \sa SDL_CreateProcess
* \sa SDL_GetProcessProperties
* \sa SDL_ReadProcess
- * \sa SDL_WriteProcess
+ * \sa SDL_GetProcessInput
+ * \sa SDL_GetProcessOutput
* \sa SDL_KillProcess
* \sa SDL_WaitProcess
* \sa SDL_DestroyProcess
@@ -248,10 +251,6 @@ extern SDL_DECLSPEC SDL_PropertiesID SDL_GetProcessProperties(SDL_Process *proce
* read the output. This function blocks until the process is complete,
* capturing all output, and providing the process exit code.
*
- * This is just a convenience function. If you need more control over the
- * process, you can get the output stream from the process properties and read
- * it directly.
- *
* The data is allocated with a zero byte at the end (null terminated) for
* convenience. This extra byte is not included in the value reported via
* `datasize`.
@@ -272,53 +271,19 @@ extern SDL_DECLSPEC SDL_PropertiesID SDL_GetProcessProperties(SDL_Process *proce
*
* \sa SDL_CreateProcess
* \sa SDL_CreateProcessWithProperties
- * \sa SDL_GetProcessProperties
- * \sa SDL_WriteProcess
* \sa SDL_DestroyProcess
*/
extern SDL_DECLSPEC void * SDLCALL SDL_ReadProcess(SDL_Process *process, size_t *datasize, int *exitcode);
/**
- * Write to a process.
- *
- * If a process was created with I/O enabled, you can use this function to
- * send data as input to the process. This function blocks until the data is
- * written.
- *
- * This is just a convenience function. If the process is structured so it
- * takes large amounts of input and generates lots of output, you should get
- * the input and output streams from the process properties and handle them
- * simultaneously to prevent the process from being blocked waiting for I/O.
- *
- * \param process The process to write.
- * \param ptr a pointer to a buffer containing data to write.
- * \param size the number of bytes to write.
- * \param closeio if SDL_TRUE, closes the process input before returning, even
- * in the case of an error.
- * \returns SDL_TRUE on success or SDL_FALSE on failure; call SDL_GetError()
- * for more information.
- *
- * \threadsafety This function is not thread safe.
- *
- * \since This function is available since SDL 3.0.0.
- *
- * \sa SDL_CreateProcess
- * \sa SDL_CreateProcessWithProperties
- * \sa SDL_GetProcessProperties
- * \sa SDL_ReadProcess
- * \sa SDL_DestroyProcess
- */
-extern SDL_DECLSPEC SDL_bool SDLCALL SDL_WriteProcess(SDL_Process *process, const void *ptr, size_t size, SDL_bool closeio);
-
-/**
- * Get the SDL_IOStream associated with process standard output.
+ * Get the SDL_IOStream associated with process standard input.
*
- * The process must have been created with I/O enabled.
+ * The process must have been created with SDL_CreateProcess() and pipe_stdio set to SDL_TRUE, or with SDL_CreateProcessWithProperties() and `SDL_PROP_PROCESS_CREATE_STDIN_NUMBER` set to `SDL_PROCESS_STDIO_APP`.
*
- * This is just a convenience function that retrieves the SDL_IOStream from the process `SDL_PROP_PROCESS_STDOUT_POINTER` property.
+ * Writing to this stream can return less data than expected if the process hasn't read its input. It may be blocked waiting for its output to be read, so if you may need to call SDL_GetOutputStream() and read the output in parallel with writing input.
*
- * \param process The process to get the output stream for.
- * \returns the output stream or NULL on failure; call SDL_GetError() for more
+ * \param process The process to get the input stream for.
+ * \returns the input stream or NULL on failure; call SDL_GetError() for more
* information.
*
* \threadsafety It is safe to call this function from any thread.
@@ -327,18 +292,19 @@ extern SDL_DECLSPEC SDL_bool SDLCALL SDL_WriteProcess(SDL_Process *process, cons
*
* \sa SDL_CreateProcess
* \sa SDL_CreateProcessWithProperties
+ * \sa SDL_GetProcessOutput
*/
-extern SDL_DECLSPEC SDL_IOStream *SDLCALL SDL_GetProcessOutputStream(SDL_Process *process);
+extern SDL_DECLSPEC SDL_IOStream *SDLCALL SDL_GetProcessInput(SDL_Process *process);
/**
- * Get the SDL_IOStream associated with process standard input.
+ * Get the SDL_IOStream associated with process standard output.
*
- * The process must have been created with I/O enabled.
+ * The process must have been created with SDL_CreateProcess() and pipe_stdio set to SDL_TRUE, or with SDL_CreateProcessWithProperties() and `SDL_PROP_PROCESS_CREATE_STDOUT_NUMBER` set to `SDL_PROCESS_STDIO_APP`.
*
- * This is just a convenience function that retrieves the SDL_IOStream from the process `SDL_PROP_PROCESS_STDIN_POINTER` property.
+ * Reading from this stream can return 0 with SDL_GetIOStatus() returning SDL_IO_STATUS_NOT_READY if no output is available yet.
*
- * \param process The process to get the input stream for.
- * \returns the input stream or NULL on failure; call SDL_GetError() for more
+ * \param process The process to get the output stream for.
+ * \returns the output stream or NULL on failure; call SDL_GetError() for more
* information.
*
* \threadsafety It is safe to call this function from any thread.
@@ -347,8 +313,9 @@ extern SDL_DECLSPEC SDL_IOStream *SDLCALL SDL_GetProcessOutputStream(SDL_Process
*
* \sa SDL_CreateProcess
* \sa SDL_CreateProcessWithProperties
+ * \sa SDL_GetProcessInput
*/
-extern SDL_DECLSPEC SDL_IOStream *SDLCALL SDL_GetProcessInputStream(SDL_Process *process);
+extern SDL_DECLSPEC SDL_IOStream *SDLCALL SDL_GetProcessOutput(SDL_Process *process);
/**
* Stop a process.
diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym
index 3067f0f4c446a..a4eb8b7192748 100644
--- a/src/dynapi/SDL_dynapi.sym
+++ b/src/dynapi/SDL_dynapi.sym
@@ -431,8 +431,8 @@ SDL3_0.0.0 {
SDL_GetPreferredLocales;
SDL_GetPrimaryDisplay;
SDL_GetPrimarySelectionText;
- SDL_GetProcessInputStream;
- SDL_GetProcessOutputStream;
+ SDL_GetProcessInput;
+ SDL_GetProcessOutput;
SDL_GetProcessProperties;
SDL_GetPropertyType;
SDL_GetRGB;
@@ -978,7 +978,6 @@ SDL3_0.0.0 {
SDL_WindowSupportsGPUPresentMode;
SDL_WindowSupportsGPUSwapchainComposition;
SDL_WriteIO;
- SDL_WriteProcess;
SDL_WriteS16BE;
SDL_WriteS16LE;
SDL_WriteS32BE;
diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h
index f8ad7502a70ab..1b4705a87688b 100644
--- a/src/dynapi/SDL_dynapi_overrides.h
+++ b/src/dynapi/SDL_dynapi_overrides.h
@@ -456,8 +456,8 @@
#define SDL_GetPreferredLocales SDL_GetPreferredLocales_REAL
#define SDL_GetPrimaryDisplay SDL_GetPrimaryDisplay_REAL
#define SDL_GetPrimarySelectionText SDL_GetPrimarySelectionText_REAL
-#define SDL_GetProcessInputStream SDL_GetProcessInputStream_REAL
-#define SDL_GetProcessOutputStream SDL_GetProcessOutputStream_REAL
+#define SDL_GetProcessInput SDL_GetProcessInput_REAL
+#define SDL_GetProcessOutput SDL_GetProcessOutput_REAL
#define SDL_GetProcessProperties SDL_GetProcessProperties_REAL
#define SDL_GetPropertyType SDL_GetPropertyType_REAL
#define SDL_GetRGB SDL_GetRGB_REAL
@@ -1003,7 +1003,6 @@
#define SDL_WindowSupportsGPUPresentMode SDL_WindowSupportsGPUPresentMode_REAL
#define SDL_WindowSupportsGPUSwapchainComposition SDL_WindowSupportsGPUSwapchainComposition_REAL
#define SDL_WriteIO SDL_WriteIO_REAL
-#define SDL_WriteProcess SDL_WriteProcess_REAL
#define SDL_WriteS16BE SDL_WriteS16BE_REAL
#define SDL_WriteS16LE SDL_WriteS16LE_REAL
#define SDL_WriteS32BE SDL_WriteS32BE_REAL
diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h
index 1395c28a7cc37..423d9948517d0 100644
--- a/src/dynapi/SDL_dynapi_procs.h
+++ b/src/dynapi/SDL_dynapi_procs.h
@@ -476,8 +476,8 @@ SDL_DYNAPI_PROC(char*,SDL_GetPrefPath,(const char *a, const char *b),(a,b),retur
SDL_DYNAPI_PROC(SDL_Locale**,SDL_GetPreferredLocales,(int *a),(a),return)
SDL_DYNAPI_PROC(SDL_DisplayID,SDL_GetPrimaryDisplay,(void),(),return)
SDL_DYNAPI_PROC(char*,SDL_GetPrimarySelectionText,(void),(),return)
-SDL_DYNAPI_PROC(SDL_IOStream*,SDL_GetProcessInputStream,(SDL_Process *a),(a),return)
-SDL_DYNAPI_PROC(SDL_IOStream*,SDL_GetProcessOutputStream,(SDL_Process *a),(a),return)
+SDL_DYNAPI_PROC(SDL_IOStream*,SDL_GetProcessInput,(SDL_Process *a),(a),return)
+SDL_DYNAPI_PROC(SDL_IOStream*,SDL_GetProcessOutput,(SDL_Process *a),(a),return)
SDL_DYNAPI_PROC(SDL_PropertiesID,SDL_GetProcessProperties,(SDL_Process *a),(a),return)
SDL_DYNAPI_PROC(SDL_PropertyType,SDL_GetPropertyType,(SDL_PropertiesID a, const char *b),(a,b),return)
SDL_DYNAPI_PROC(void,SDL_GetRGB,(Uint32 a, const SDL_PixelFormatDetails *b, const SDL_Palette *c, Uint8 *d, Uint8 *e, Uint8 *f),(a,b,c,d,e,f),)
@@ -1013,7 +1013,6 @@ SDL_DYNAPI_PROC(SDL_bool,SDL_WindowHasSurface,(SDL_Window *a),(a),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_WindowSupportsGPUPresentMode,(SDL_GPUDevice *a, SDL_Window *b, SDL_GPUPresentMode c),(a,b,c),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_WindowSupportsGPUSwapchainComposition,(SDL_GPUDevice *a, SDL_Window *b, SDL_GPUSwapchainComposition c),(a,b,c),return)
SDL_DYNAPI_PROC(size_t,SDL_WriteIO,(SDL_IOStream *a, const void *b, size_t c),(a,b,c),return)
-SDL_DYNAPI_PROC(SDL_bool,SDL_WriteProcess,(SDL_Process *a, const void *b, size_t c, SDL_bool d),(a,b,c,d),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_WriteS16BE,(SDL_IOStream *a, Sint16 b),(a,b),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_WriteS16LE,(SDL_IOStream *a, Sint16 b),(a,b),return)
SDL_DYNAPI_PROC(SDL_bool,SDL_WriteS32BE,(SDL_IOStream *a, Sint32 b),(a,b),return)
diff --git a/src/process/SDL_process.c b/src/process/SDL_process.c
index 6521b1296def5..c42b2d21ec5c6 100644
--- a/src/process/SDL_process.c
+++ b/src/process/SDL_process.c
@@ -108,77 +108,32 @@ void *SDL_ReadProcess(SDL_Process *process, size_t *datasize, int *exitcode)
return result;
}
-SDL_bool SDL_WriteProcess(SDL_Process *process, const void *ptr, size_t size, SDL_bool closeio)
-{
- bool result = false;
- SDL_IOStream *io = NULL;
-
- if (!process) {
- SDL_InvalidParamError("process");
- goto done;
- }
-
- io = (SDL_IOStream *)SDL_GetPointerProperty(process->props, SDL_PROP_PROCESS_STDIN_POINTER, NULL);
- if (!io) {
- SDL_SetError("Process not created with I/O enabled");
- goto done;
- }
-
- size_t written = 0, left = size;
- while (left > 0) {
- size_t amount = SDL_WriteIO(io, (Uint8 *)ptr + written, left);
- if (amount > 0) {
- written += amount;
- left -= amount;
- continue;
- } else if (SDL_GetIOStatus(io) == SDL_IO_STATUS_NOT_READY) {
- // Wait for the stream to be ready
- SDL_Delay(1);
- continue;
- }
-
- // The stream status will remain set for the caller to check
- break;
- }
-
- result = (written == size);
-
-done:
- if (result) {
- result = SDL_FlushIO(io);
- }
- if (closeio) {
- result &= SDL_CloseIO(io);
- }
- return result;
-}
-
-SDL_IOStream *SDL_GetProcessOutputStream(SDL_Process *process)
+SDL_IOStream *SDL_GetProcessInput(SDL_Process *process)
{
if (!process) {
SDL_InvalidParamError("process");
return NULL;
}
- SDL_IOStream *io = (SDL_IOStream *)SDL_GetPointerProperty(process->props, SDL_PROP_PROCESS_STDOUT_POINTER, NULL);
+ SDL_IOStream *io = (SDL_IOStream *)SDL_GetPointerProperty(process->props, SDL_PROP_PROCESS_STDIN_POINTER, NULL);
if (!io) {
- SDL_SetError("Process not created with I/O enabled");
+ SDL_SetError("Process not created with standard input available");
return NULL;
}
return io;
}
-SDL_IOStream *SDL_GetProcessInputStream(SDL_Process *process)
+SDL_IOStream *SDL_GetProcessOutput(SDL_Process *process)
{
if (!process) {
SDL_InvalidParamError("process");
return NULL;
}
- SDL_IOStream *io = (SDL_IOStream *)SDL_GetPointerProperty(process->props, SDL_PROP_PROCESS_STDIN_POINTER, NULL);
+ SDL_IOStream *io = (SDL_IOStream *)SDL_GetPointerProperty(process->props, SDL_PROP_PROCESS_STDOUT_POINTER, NULL);
if (!io) {
- SDL_SetError("Process not created with I/O enabled");
+ SDL_SetError("Process not created with standard output available");
return NULL;
}
diff --git a/test/testprocess.c b/test/testprocess.c
index cc14fe780ec2e..576ab0f0cb763 100644
--- a/test/testprocess.c
+++ b/test/testprocess.c
@@ -172,7 +172,7 @@ static int SDLCALL process_testInheritedEnv(void *arg)
pid = SDL_GetNumberProperty(props, SDL_PROP_PROCESS_PID_NUMBER, 0);
SDLTest_AssertCheck(pid != 0, "Checking process ID, expected non-zero, got %" SDL_PRIs64, pid);
- process_stdout = SDL_GetProcessOutputStream(process);
+ process_stdout = SDL_GetProcessOutput(process);
SDLTest_AssertCheck(process_stdout != NULL, "SDL_GetPointerProperty(SDL_PROP_PROCESS_STDOUT_POINTER) returns a valid IO stream");
if (!process_stdout) {
goto failed;
@@ -250,7 +250,7 @@ static int SDLCALL process_testNewEnv(void *arg)
pid = SDL_GetNumberProperty(props, SDL_PROP_PROCESS_PID_NUMBER, 0);
SDLTest_AssertCheck(pid != 0, "Checking process ID, expected non-zero, got %" SDL_PRIs64, pid);
- process_stdout = SDL_GetProcessOutputStream(process);
+ process_stdout = SDL_GetProcessOutput(process);
SDLTest_AssertCheck(process_stdout != NULL, "SDL_GetPointerProperty(SDL_PROP_PROCESS_STDOUT_POINTER) returns a valid IO stream");
if (!process_stdout) {
goto failed;
@@ -326,9 +326,9 @@ static int process_testStdinToStdout(void *arg)
pid = SDL_GetNumberProperty(props, SDL_PROP_PROCESS_PID_NUMBER, 0);
SDLTest_AssertCheck(pid != 0, "Checking process ID, expected non-zero, got %" SDL_PRIs64, pid);
- process_stdin = SDL_GetProcessInputStream(process);
+ process_stdin = SDL_GetProcessInput(process);
SDLTest_AssertCheck(process_stdin != NULL, "SDL_GetPointerProperty(SDL_PROP_PROCESS_STDIN_POINTER) returns a valid IO stream");
- process_stdout = SDL_GetProcessOutputStream(process);
+ process_stdout = SDL_GetProcessOutput(process);
SDLTest_AssertCheck(process_stdout != NULL, "SDL_GetPointerProperty(SDL_PROP_PROCESS_STDOUT_POINTER) returns a valid IO stream");
if (!process_stdin || !process_stdout) {
goto failed;
@@ -370,7 +370,7 @@ static int process_testStdinToStdout(void *arg)
/* Closing stdin of `subprocessstdin --stdin-to-stdout` should close the process */
SDL_CloseIO(process_stdin);
- process_stdin = SDL_GetProcessInputStream(process);
+ process_stdin = SDL_GetProcessInput(process);
SDLTest_AssertCheck(process_stdin == NULL, "SDL_GetPointerProperty(SDL_PROP_PROCESS_STDIN_POINTER) is cleared after close");
SDLTest_AssertPass("About to wait on process");
@@ -402,9 +402,10 @@ static int process_testSimpleStdinToStdout(void *arg)
NULL,
};
SDL_Process *process = NULL;
+ SDL_IOStream *input = NULL;
const char *text_in = "Tests whether we can write to stdin and read from stdout\r\n{'succes': true, 'message': 'Success!'}\r\nYippie ka yee\r\nEOF";
char *buffer;
- SDL_bool result;
+ size_t result;
int exit_code;
process = SDL_CreateProcess(process_args, SDL_TRUE);
@@ -414,11 +415,14 @@ static int process_testSimpleStdinToStdout(void *arg)
}
SDLTest_AssertPass("About to write to process");
- result = SDL_WriteProcess(process, text_in, SDL_strlen(text_in), SDL_TRUE);
- SDLTest_AssertCheck(result, "SDL_WriteProcess()");
- if (!result) {
- goto failed;
- }
+ input = SDL_GetProcessInput(process);
+ SDLTest_AssertCheck(input != NULL, "SDL_GetProcessInput()");
+ result = SDL_WriteIO(input, text_in, SDL_strlen(text_in));
+ SDLTest_AssertCheck(result == SDL_strlen(text_in), "SDL_WriteIO() wrote %d, expected %d", (int)result, (int)SDL_strlen(text_in));
+ SDL_CloseIO(input);
+
+ input = SDL_GetProcessInput(process);
+ SDLTest_AssertCheck(input == NULL, "SDL_GetProcessInput() after close");
exit_code = 0xdeadbeef;
buffer = (char *)SDL_ReadProcess(process, NULL, &exit_code);
@@ -452,9 +456,10 @@ static int process_testMultiprocessStdinToStdout(void *arg)
SDL_Process *process1 = NULL;
SDL_Process *process2 = NULL;
SDL_PropertiesID props;
+ SDL_IOStream *input = NULL;
const char *text_in = "Tests whether we can write to stdin and read from stdout\r\n{'succes': true, 'message': 'Success!'}\r\nYippie ka yee\r\nEOF";
char *buffer;
- SDL_bool result;
+ size_t result;
int exit_code;
process1 = SDL_CreateProcess(process_args, SDL_TRUE);
@@ -476,11 +481,11 @@ static int process_testMultiprocessStdinToStdout(void *arg)
}
SDLTest_AssertPass("About to write to process");
- result = SDL_WriteProcess(process1, text_in, SDL_strlen(text_in), SDL_TRUE);
- SDLTest_AssertCheck(result, "SDL_WriteProcess()");
- if (!result) {
- goto failed;
- }
+ input = SDL_GetProcessInput(process1);
+ SDLTest_AssertCheck(input != NULL, "SDL_GetProcessInput()");
+ result = SDL_WriteIO(input, text_in, SDL_strlen(text_in));
+ SDLTest_AssertCheck(result == SDL_strlen(text_in), "SDL_WriteIO() wrote %d, expected %d", (int)result, (int)SDL_strlen(text_in));
+ SDL_CloseIO(input);
exit_code = 0xdeadbeef;
buffer = (char *)SDL_ReadProcess(process2, NULL, &exit_code);