From 5c9860a0a2bf27d409c986673f0a74542561c4c3 Mon Sep 17 00:00:00 2001 From: Sander Bosma Date: Wed, 1 Mar 2017 10:43:47 +0100 Subject: api: Do not truncate errors <1 MB. #6237 Closes #5984 --- src/nvim/api/private/helpers.c | 113 +++++++++++++++++++++++++---------------- 1 file changed, 69 insertions(+), 44 deletions(-) (limited to 'src/nvim/api/private/helpers.c') diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 5877b848fc..e6632525e1 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -61,7 +61,7 @@ bool try_end(Error *err) discard_current_exception(); } - api_set_error(err, Exception, _("Keyboard interrupt")); + _api_set_error(err, kErrorTypeException, _("Keyboard interrupt")); got_int = false; } else if (msg_list != NULL && *msg_list != NULL) { int should_free; @@ -69,15 +69,14 @@ bool try_end(Error *err) ET_ERROR, NULL, &should_free); - xstrlcpy(err->msg, msg, sizeof(err->msg)); - err->set = true; + _api_set_error(err, err->type, "%s", msg); free_global_msglist(); if (should_free) { xfree(msg); } } else if (did_throw) { - api_set_error(err, Exception, "%s", current_exception->value); + _api_set_error(err, kErrorTypeException, "%s", current_exception->value); discard_current_exception(); } @@ -94,7 +93,7 @@ Object dict_get_value(dict_T *dict, String key, Error *err) dictitem_T *const di = tv_dict_find(dict, key.data, (ptrdiff_t)key.size); if (di == NULL) { - api_set_error(err, Validation, _("Key not found")); + _api_set_error(err, kErrorTypeValidation, _("Key not found")); return (Object) OBJECT_INIT; } @@ -118,17 +117,17 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, Object rv = OBJECT_INIT; if (dict->dv_lock) { - api_set_error(err, Exception, _("Dictionary is locked")); + _api_set_error(err, kErrorTypeException, _("Dictionary is locked")); return rv; } if (key.size == 0) { - api_set_error(err, Validation, _("Empty variable names aren't allowed")); + _api_set_error(err, kErrorTypeValidation, _("Empty variable names aren't allowed")); return rv; } if (key.size > INT_MAX) { - api_set_error(err, Validation, _("Key length is too high")); + _api_set_error(err, kErrorTypeValidation, _("Key length is too high")); return rv; } @@ -136,13 +135,13 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, if (di != NULL) { if (di->di_flags & DI_FLAGS_RO) { - api_set_error(err, Exception, _("Key is read-only: %s"), key.data); + _api_set_error(err, kErrorTypeException, _("Key is read-only: %s"), key.data); return rv; } else if (di->di_flags & DI_FLAGS_FIX) { - api_set_error(err, Exception, _("Key is fixed: %s"), key.data); + _api_set_error(err, kErrorTypeException, _("Key is fixed: %s"), key.data); return rv; } else if (di->di_flags & DI_FLAGS_LOCK) { - api_set_error(err, Exception, _("Key is locked: %s"), key.data); + _api_set_error(err, kErrorTypeException, _("Key is locked: %s"), key.data); return rv; } } @@ -151,7 +150,7 @@ Object dict_set_var(dict_T *dict, String key, Object value, bool del, // Delete the key if (di == NULL) { // Doesn't exist, fail - api_set_error(err, Validation, _("Key \"%s\" doesn't exist"), key.data); + _api_set_error(err, kErrorTypeValidation, _("Key \"%s\" doesn't exist"), key.data); } else { // Return the old value if (retval) { @@ -203,7 +202,7 @@ Object get_option_from(void *from, int type, String name, Error *err) Object rv = OBJECT_INIT; if (name.size == 0) { - api_set_error(err, Validation, _("Empty option name")); + _api_set_error(err, kErrorTypeValidation, _("Empty option name")); return rv; } @@ -214,8 +213,8 @@ Object get_option_from(void *from, int type, String name, Error *err) type, from); if (!flags) { - api_set_error(err, - Validation, + _api_set_error(err, + kErrorTypeValidation, _("Invalid option name \"%s\""), name.data); return rv; @@ -233,14 +232,14 @@ Object get_option_from(void *from, int type, String name, Error *err) rv.data.string.data = stringval; rv.data.string.size = strlen(stringval); } else { - api_set_error(err, - Exception, + _api_set_error(err, + kErrorTypeException, _("Unable to get value for option \"%s\""), name.data); } } else { - api_set_error(err, - Exception, + _api_set_error(err, + kErrorTypeException, _("Unknown type for option \"%s\""), name.data); } @@ -258,15 +257,15 @@ Object get_option_from(void *from, int type, String name, Error *err) void set_option_to(void *to, int type, String name, Object value, Error *err) { if (name.size == 0) { - api_set_error(err, Validation, _("Empty option name")); + _api_set_error(err, kErrorTypeValidation, _("Empty option name")); return; } int flags = get_option_value_strict(name.data, NULL, NULL, type, to); if (flags == 0) { - api_set_error(err, - Validation, + _api_set_error(err, + kErrorTypeValidation, _("Invalid option name \"%s\""), name.data); return; @@ -274,14 +273,14 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) if (value.type == kObjectTypeNil) { if (type == SREQ_GLOBAL) { - api_set_error(err, - Exception, + _api_set_error(err, + kErrorTypeException, _("Unable to unset option \"%s\""), name.data); return; } else if (!(flags & SOPT_GLOBAL)) { - api_set_error(err, - Exception, + _api_set_error(err, + kErrorTypeException, _("Cannot unset option \"%s\" " "because it doesn't have a global value"), name.data); @@ -296,8 +295,8 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) if (flags & SOPT_BOOL) { if (value.type != kObjectTypeBoolean) { - api_set_error(err, - Validation, + _api_set_error(err, + kErrorTypeValidation, _("Option \"%s\" requires a boolean value"), name.data); return; @@ -307,16 +306,16 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) set_option_value_for(name.data, val, NULL, opt_flags, type, to, err); } else if (flags & SOPT_NUM) { if (value.type != kObjectTypeInteger) { - api_set_error(err, - Validation, + _api_set_error(err, + kErrorTypeValidation, _("Option \"%s\" requires an integer value"), name.data); return; } if (value.data.integer > INT_MAX || value.data.integer < INT_MIN) { - api_set_error(err, - Validation, + _api_set_error(err, + kErrorTypeValidation, _("Value for option \"%s\" is outside range"), name.data); return; @@ -326,8 +325,8 @@ void set_option_to(void *to, int type, String name, Object value, Error *err) set_option_value_for(name.data, val, NULL, opt_flags, type, to, err); } else { if (value.type != kObjectTypeString) { - api_set_error(err, - Validation, + _api_set_error(err, + kErrorTypeValidation, _("Option \"%s\" requires a string value"), name.data); return; @@ -561,13 +560,13 @@ buf_T *find_buffer_by_handle(Buffer buffer, Error *err) buf_T *rv = handle_get_buffer(buffer); if (!rv) { - api_set_error(err, Validation, _("Invalid buffer id")); + _api_set_error(err, kErrorTypeValidation, _("Invalid buffer id")); } return rv; } -win_T * find_window_by_handle(Window window, Error *err) +win_T *find_window_by_handle(Window window, Error *err) { if (window == 0) { return curwin; @@ -576,13 +575,13 @@ win_T * find_window_by_handle(Window window, Error *err) win_T *rv = handle_get_window(window); if (!rv) { - api_set_error(err, Validation, _("Invalid window id")); + _api_set_error(err, kErrorTypeValidation, _("Invalid window id")); } return rv; } -tabpage_T * find_tab_by_handle(Tabpage tabpage, Error *err) +tabpage_T *find_tab_by_handle(Tabpage tabpage, Error *err) { if (tabpage == 0) { return curtab; @@ -591,7 +590,7 @@ tabpage_T * find_tab_by_handle(Tabpage tabpage, Error *err) tabpage_T *rv = handle_get_tabpage(tabpage); if (!rv) { - api_set_error(err, Validation, _("Invalid tabpage id")); + _api_set_error(err, kErrorTypeValidation, _("Invalid tabpage id")); } return rv; @@ -659,7 +658,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err) case kObjectTypeInteger: if (obj.data.integer > VARNUMBER_MAX || obj.data.integer < VARNUMBER_MIN) { - api_set_error(err, Validation, _("Integer value outside range")); + _api_set_error(err, kErrorTypeValidation, _("Integer value outside range")); return false; } @@ -713,7 +712,7 @@ bool object_to_vim(Object obj, typval_T *tv, Error *err) String key = item.key; if (key.size == 0) { - api_set_error(err, Validation, + _api_set_error(err, kErrorTypeValidation, _("Empty dictionary keys aren't allowed")); // cleanup tv_dict_free(dict); @@ -801,6 +800,12 @@ void api_free_dictionary(Dictionary value) xfree(value.items); } +void api_free_error(Error *value) +{ + xfree(value->msg); + value->msg = NULL; +} + Dictionary api_metadata(void) { static Dictionary metadata = ARRAY_DICT_INIT; @@ -926,8 +931,8 @@ static void set_option_value_for(char *key, if (try_end(err)) { return; } - api_set_error(err, - Exception, + _api_set_error(err, + kErrorTypeException, _("Problem while switching windows")); return; } @@ -965,6 +970,26 @@ static void set_option_value_err(char *key, return; } - api_set_error(err, Exception, "%s", errmsg); + _api_set_error(err, kErrorTypeException, "%s", errmsg); } } + +void _api_set_error(Error *err, ErrorType errType, const char *format, ...) + FUNC_ATTR_NONNULL_ALL +{ + va_list args1; + va_list args2; + va_start(args1, format); + va_copy(args2, args1); + int len = vsnprintf(NULL, 0, format, args1); + va_end(args1); + assert(len >= 0); + // Limit error message to 1 MB. + size_t bufsize = MIN((size_t)len + 1, 1024 * 1024); + err->msg = xmalloc(bufsize); + vsnprintf(err->msg, bufsize, format, args2); + va_end(args2); + + err->set = true; + err->type = errType; +} -- cgit