Adjust error handling in libwinpty

* Use ASSERT() where the API is being misused.  Also use it when
   WaitForMultipleObjects or WriteFile return a value I don't expect to
   ever see.

 * Allow passing err to winpty_error_{code,msg}, though.  Instead of
   complaining about the NULL error pointer, instead return
   WINPTY_ERROR_SUCCESS and L"Success".
This commit is contained in:
Ryan Prichard 2016-01-23 04:12:25 -06:00
parent 6deb5e2c26
commit cfb5f81de3
2 changed files with 29 additions and 45 deletions

View File

@ -37,16 +37,16 @@
/***************************************************************************** /*****************************************************************************
* Error codes. */ * Error codes. */
#define WINPTY_ERROR_SUCCESS 0
#define WINPTY_ERROR_OUT_OF_MEMORY 1 #define WINPTY_ERROR_OUT_OF_MEMORY 1
#define WINPTY_ERROR_SPAWN_CREATE_PROCESS_FAILED 2 #define WINPTY_ERROR_SPAWN_CREATE_PROCESS_FAILED 2
#define WINPTY_ERROR_INVALID_ARGUMENT 3 #define WINPTY_ERROR_LOST_CONNECTION 3
#define WINPTY_ERROR_LOST_CONNECTION 4 #define WINPTY_ERROR_AGENT_EXE_MISSING 4
#define WINPTY_ERROR_AGENT_EXE_MISSING 5 #define WINPTY_ERROR_WINDOWS_ERROR 5
#define WINPTY_ERROR_WINDOWS_ERROR 6 #define WINPTY_ERROR_INTERNAL_ERROR 6
#define WINPTY_ERROR_INTERNAL_ERROR 7 #define WINPTY_ERROR_AGENT_DIED 7
#define WINPTY_ERROR_AGENT_DIED 8 #define WINPTY_ERROR_AGENT_TIMEOUT 8
#define WINPTY_ERROR_AGENT_TIMEOUT 9 #define WINPTY_ERROR_AGENT_CREATION_FAILED 9
#define WINPTY_ERROR_AGENT_CREATION_FAILED 10

View File

@ -37,6 +37,7 @@
#include "../shared/GenRandom.h" #include "../shared/GenRandom.h"
#include "../shared/StringBuilder.h" #include "../shared/StringBuilder.h"
#include "../shared/WindowsSecurity.h" #include "../shared/WindowsSecurity.h"
#include "../shared/WinptyAssert.h"
#include "BackgroundDesktop.h" #include "BackgroundDesktop.h"
#include "Util.h" #include "Util.h"
#include "WinptyException.h" #include "WinptyException.h"
@ -54,13 +55,11 @@ using namespace winpty_shared;
* output and log the result. */ * output and log the result. */
WINPTY_API winpty_result_t winpty_error_code(winpty_error_ptr_t err) { WINPTY_API winpty_result_t winpty_error_code(winpty_error_ptr_t err) {
return err != nullptr ? err->code return err == nullptr ? WINPTY_ERROR_SUCCESS : err->code;
: WINPTY_ERROR_INVALID_ARGUMENT;
} }
WINPTY_API LPCWSTR winpty_error_msg(winpty_error_ptr_t err) { WINPTY_API LPCWSTR winpty_error_msg(winpty_error_ptr_t err) {
return err != nullptr ? err->msg return err == nullptr ? L"Success" : err->msg;
: L"winpty_error_str argument is NULL";
} }
WINPTY_API void winpty_error_free(winpty_error_ptr_t err) { WINPTY_API void winpty_error_free(winpty_error_ptr_t err) {
@ -70,11 +69,6 @@ WINPTY_API void winpty_error_free(winpty_error_ptr_t err) {
} }
} }
STATIC_ERROR(kInvalidArgument,
WINPTY_ERROR_INVALID_ARGUMENT,
L"invalid argument"
);
STATIC_ERROR(kBadRpcPacket, STATIC_ERROR(kBadRpcPacket,
WINPTY_ERROR_INTERNAL_ERROR, WINPTY_ERROR_INTERNAL_ERROR,
L"bad RPC packet" L"bad RPC packet"
@ -107,16 +101,6 @@ static void translateException(winpty_error_ptr_t *&err) {
} }
} }
static void throwInvalidArgument() {
throwStaticError(kInvalidArgument);
}
static inline void require_arg(bool cond) {
if (!cond) {
throwInvalidArgument();
}
}
#define API_TRY \ #define API_TRY \
if (err != nullptr) { *err = nullptr; } \ if (err != nullptr) { *err = nullptr; } \
try try
@ -132,7 +116,7 @@ static inline void require_arg(bool cond) {
WINPTY_API winpty_config_t * WINPTY_API winpty_config_t *
winpty_config_new(DWORD flags, winpty_error_ptr_t *err /*OPTIONAL*/) { winpty_config_new(DWORD flags, winpty_error_ptr_t *err /*OPTIONAL*/) {
API_TRY { API_TRY {
require_arg((flags & WINPTY_FLAG_MASK) == flags); ASSERT((flags & WINPTY_FLAG_MASK) == flags);
std::unique_ptr<winpty_config_t> ret(new winpty_config_t); std::unique_ptr<winpty_config_t> ret(new winpty_config_t);
ret->flags = flags; ret->flags = flags;
return ret.release(); return ret.release();
@ -147,7 +131,7 @@ WINPTY_API BOOL
winpty_config_set_initial_size(winpty_config_t *cfg, int cols, int rows, winpty_config_set_initial_size(winpty_config_t *cfg, int cols, int rows,
winpty_error_ptr_t *err /*OPTIONAL*/) { winpty_error_ptr_t *err /*OPTIONAL*/) {
API_TRY { API_TRY {
require_arg(cfg != nullptr && cols > 0 && rows > 0); ASSERT(cfg != nullptr && cols > 0 && rows > 0);
cfg->cols = cols; cfg->cols = cols;
cfg->rows = rows; cfg->rows = rows;
return TRUE; return TRUE;
@ -158,7 +142,7 @@ WINPTY_API BOOL
winpty_config_set_agent_timeout(winpty_config_t *cfg, DWORD timeoutMs, winpty_config_set_agent_timeout(winpty_config_t *cfg, DWORD timeoutMs,
winpty_error_ptr_t *err /*OPTIONAL*/) { winpty_error_ptr_t *err /*OPTIONAL*/) {
API_TRY { API_TRY {
require_arg(cfg != nullptr && timeoutMs > 0); ASSERT(cfg != nullptr && timeoutMs > 0);
cfg->timeoutMs = timeoutMs; cfg->timeoutMs = timeoutMs;
return TRUE; return TRUE;
} API_CATCH(FALSE) } API_CATCH(FALSE)
@ -202,8 +186,8 @@ static void handlePendingIo(winpty_t *wp, OVERLAPPED &over, BOOL &success,
} else if (waitRet == WAIT_FAILED) { } else if (waitRet == WAIT_FAILED) {
throwLastWindowsError(L"WaitForMultipleObjects failed"); throwLastWindowsError(L"WaitForMultipleObjects failed");
} else { } else {
throwWinptyException(WINPTY_ERROR_INTERNAL_ERROR, ASSERT(false &&
L"unexpected WaitForMultipleObjects return value"); "unexpected WaitForMultipleObjects return value");
} }
} }
success = io.waitForCompletion(actual); success = io.waitForCompletion(actual);
@ -257,13 +241,10 @@ static void writeData(winpty_t *wp, const void *data, size_t amount) {
if (!success) { if (!success) {
handlePendingIo(wp, over, success, actual); handlePendingIo(wp, over, success, actual);
handleReadWriteErrors(wp, success, L"WriteFile failed"); handleReadWriteErrors(wp, success, L"WriteFile failed");
ASSERT(success);
} }
if (actual != amount) { // TODO: Can a partial write actually happen somehow?
// TODO: We failed during the write. We *probably* should permanently ASSERT(actual == amount && "WriteFile wrote fewer bytes than requested");
// shut things down, disconnect at least the control pipe.
throwWinptyException(WINPTY_ERROR_INTERNAL_ERROR,
L"WriteFile wrote fewer bytes than requested");
}
} }
static void writePacket(winpty_t *wp, WriteBuffer &packet) { static void writePacket(winpty_t *wp, WriteBuffer &packet) {
@ -390,7 +371,7 @@ WINPTY_API winpty_t *
winpty_open(const winpty_config_t *cfg, winpty_open(const winpty_config_t *cfg,
winpty_error_ptr_t *err /*OPTIONAL*/) { winpty_error_ptr_t *err /*OPTIONAL*/) {
API_TRY { API_TRY {
require_arg(cfg != nullptr); ASSERT(cfg != nullptr);
std::unique_ptr<winpty_t> wp(new winpty_t); std::unique_ptr<winpty_t> wp(new winpty_t);
wp->agentTimeoutMs = cfg->timeoutMs; wp->agentTimeoutMs = cfg->timeoutMs;
@ -432,7 +413,8 @@ winpty_open(const winpty_config_t *cfg,
} }
WINPTY_API HANDLE winpty_agent_process(winpty_t *wp) { WINPTY_API HANDLE winpty_agent_process(winpty_t *wp) {
return wp == nullptr ? nullptr : wp->agentProcess.get(); ASSERT(wp != nullptr);
return wp->agentProcess.get();
} }
@ -441,10 +423,12 @@ WINPTY_API HANDLE winpty_agent_process(winpty_t *wp) {
* I/O pipes. */ * I/O pipes. */
WINPTY_API LPCWSTR winpty_conin_name(winpty_t *wp) { WINPTY_API LPCWSTR winpty_conin_name(winpty_t *wp) {
return wp == nullptr ? nullptr : cstrFromWStringOrNull(wp->coninPipeName); ASSERT(wp != nullptr);
return cstrFromWStringOrNull(wp->coninPipeName);
} }
WINPTY_API LPCWSTR winpty_conout_name(winpty_t *wp) { WINPTY_API LPCWSTR winpty_conout_name(winpty_t *wp) {
return wp == nullptr ? nullptr : cstrFromWStringOrNull(wp->conoutPipeName); ASSERT(wp != nullptr);
return cstrFromWStringOrNull(wp->conoutPipeName);
} }
@ -460,7 +444,7 @@ winpty_spawn_config_new(DWORD winptyFlags,
LPCWSTR env /*OPTIONAL*/, LPCWSTR env /*OPTIONAL*/,
winpty_error_ptr_t *err /*OPTIONAL*/) { winpty_error_ptr_t *err /*OPTIONAL*/) {
API_TRY { API_TRY {
require_arg((winptyFlags & WINPTY_SPAWN_FLAG_MASK) == winptyFlags); ASSERT((winptyFlags & WINPTY_SPAWN_FLAG_MASK) == winptyFlags);
std::unique_ptr<winpty_spawn_config_t> cfg(new winpty_spawn_config_t); std::unique_ptr<winpty_spawn_config_t> cfg(new winpty_spawn_config_t);
cfg->winptyFlags = winptyFlags; cfg->winptyFlags = winptyFlags;
if (appname != nullptr) { cfg->appname = appname; } if (appname != nullptr) { cfg->appname = appname; }
@ -510,7 +494,7 @@ winpty_spawn(winpty_t *wp,
if (thread_handle != nullptr) { *thread_handle = nullptr; } if (thread_handle != nullptr) { *thread_handle = nullptr; }
if (create_process_error != nullptr) { *create_process_error = 0; } if (create_process_error != nullptr) { *create_process_error = 0; }
API_TRY { API_TRY {
require_arg(wp != nullptr && cfg != nullptr); ASSERT(wp != nullptr && cfg != nullptr);
winpty_cxx11::lock_guard<winpty_cxx11::mutex> lock(wp->mutex); winpty_cxx11::lock_guard<winpty_cxx11::mutex> lock(wp->mutex);
// Send spawn request. // Send spawn request.
@ -580,7 +564,7 @@ WINPTY_API BOOL
winpty_set_size(winpty_t *wp, int cols, int rows, winpty_set_size(winpty_t *wp, int cols, int rows,
winpty_error_ptr_t *err /*OPTIONAL*/) { winpty_error_ptr_t *err /*OPTIONAL*/) {
API_TRY { API_TRY {
require_arg(wp != nullptr && cols > 0 && rows > 0); ASSERT(wp != nullptr && cols > 0 && rows > 0);
winpty_cxx11::lock_guard<winpty_cxx11::mutex> lock(wp->mutex); winpty_cxx11::lock_guard<winpty_cxx11::mutex> lock(wp->mutex);
WriteBuffer packet; WriteBuffer packet;
packet.putRawInt32(0); // payload size packet.putRawInt32(0); // payload size