diff options
author | Aaron Plattner <aplattner@nvidia.com> | 2019-04-23 11:11:51 -0700 |
---|---|---|
committer | Aaron Plattner <aplattner@nvidia.com> | 2019-04-23 11:11:51 -0700 |
commit | 6750128dd06d682d260355d49692ceda2f352ef4 (patch) | |
tree | b63b1dc0b41509e0c56585338c0b87109f5f2b04 | |
parent | f2a3b63791beb6b5a7e509de457c690a96667395 (diff) |
430.09430.09
32 files changed, 973 insertions, 525 deletions
diff --git a/doc/version.mk b/doc/version.mk index 6942222..5e94d96 100644 --- a/doc/version.mk +++ b/doc/version.mk @@ -1 +1 @@ -NVIDIA_VERSION = 418.56 +NVIDIA_VERSION = 430.09 diff --git a/samples/version.mk b/samples/version.mk index 6942222..5e94d96 100644 --- a/samples/version.mk +++ b/samples/version.mk @@ -1 +1 @@ -NVIDIA_VERSION = 418.56 +NVIDIA_VERSION = 430.09 diff --git a/src/XF86Config-parser/Generate.c b/src/XF86Config-parser/Generate.c index 1f8ffca..b446558 100644 --- a/src/XF86Config-parser/Generate.c +++ b/src/XF86Config-parser/Generate.c @@ -426,16 +426,6 @@ XConfigMonitorPtr xconfigAddMonitor(XConfigPtr config, int count) monitor->vendor = xconfigStrdup("Unknown"); /* XXX */ monitor->modelname = xconfigStrdup("Unknown"); /* XXX */ - /* XXX check EDID for freq ranges */ - - monitor->n_hsync = 1; - monitor->hsync[0].lo = 28.0; - monitor->hsync[0].hi = 33.0; - - monitor->n_vrefresh = 1; - monitor->vrefresh[0].lo = 43.0; - monitor->vrefresh[0].hi = 72.0; - monitor->options = NULL; xconfigAddNewOption(&monitor->options, "DPMS", NULL); diff --git a/src/gtk+-2.x/ctkappprofile.c b/src/gtk+-2.x/ctkappprofile.c index b070f02..b6253d7 100644 --- a/src/gtk+-2.x/ctkappprofile.c +++ b/src/gtk+-2.x/ctkappprofile.c @@ -2030,7 +2030,7 @@ static EditRuleDialog* edit_rule_dialog_new(CtkAppProfile *ctk_app_profile) dialog->parent = GTK_WIDGET(ctk_app_profile); dialog->top_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_modal(GTK_WINDOW(dialog->top_window), TRUE); + gtk_window_set_modal(GTK_WINDOW(dialog->top_window), FALSE); g_signal_connect(G_OBJECT(dialog->top_window), "delete-event", G_CALLBACK(edit_rule_dialog_handle_delete), dialog); @@ -2996,7 +2996,7 @@ static EditProfileDialog *edit_profile_dialog_new(CtkAppProfile *ctk_app_profile dialog->setting_toolbar_help_data = NULL; dialog->bottom_help_data = NULL; - gtk_window_set_modal(GTK_WINDOW(dialog->top_window), TRUE); + gtk_window_set_modal(GTK_WINDOW(dialog->top_window), FALSE); g_signal_connect(G_OBJECT(dialog->top_window), "delete-event", G_CALLBACK(edit_profile_dialog_handle_delete), dialog); diff --git a/src/gtk+-2.x/ctkframelock.c b/src/gtk+-2.x/ctkframelock.c index 6f51e23..12bd8ff 100644 --- a/src/gtk+-2.x/ctkframelock.c +++ b/src/gtk+-2.x/ctkframelock.c @@ -4328,7 +4328,7 @@ static void display_state_received(GObject *object, if (!display_entry || !display_entry->data || - !display_entry->data_type != ENTRY_DATA_DISPLAY) { + display_entry->data_type != ENTRY_DATA_DISPLAY) { return; } @@ -4383,7 +4383,7 @@ static void gpu_state_received(GObject *object, if (!gpu_entry || !gpu_entry->data || - !gpu_entry->data_type != ENTRY_DATA_GPU) { + gpu_entry->data_type != ENTRY_DATA_GPU) { return; } diff --git a/src/gtk+-2.x/ctkgridlicense.c b/src/gtk+-2.x/ctkgridlicense.c index 4280b08..2d36867 100644 --- a/src/gtk+-2.x/ctkgridlicense.c +++ b/src/gtk+-2.x/ctkgridlicense.c @@ -119,7 +119,7 @@ static gboolean allow_digits(GtkWidget *widget, GdkEvent *event, gpointer user_d static gboolean enable_disable_ui_controls(GtkWidget *widget, GdkEvent *event, gpointer user_data); static void update_gui_from_griddconfig(gpointer user_data); static gboolean licenseStateQueryFailed = FALSE; -static void get_licensed_feature_information(gpointer user_data); +static void get_licensable_feature_information(gpointer user_data); static gboolean is_restart_required(gpointer user_data); static gboolean queryLicensedFeatureCode = TRUE; int64_t licensedFeatureCode = NV_GRID_LICENSE_FEATURE_TYPE_VAPP; @@ -843,7 +843,7 @@ static gboolean update_manage_grid_license_state_info(gpointer user_data) break; } if (queryLicensedFeatureCode == TRUE) { - get_licensed_feature_information(ctk_manage_grid_license); + get_licensable_feature_information(ctk_manage_grid_license); queryLicensedFeatureCode = FALSE; } } @@ -1080,9 +1080,9 @@ static void apply_clicked(GtkWidget *widget, gpointer user_data) } /* - * get_licensed_feature_information() - Get the details of the feature that is licensed on this system. + * get_licensable_feature_information() - Get the details of the supported licensable features on the system. */ -static void get_licensed_feature_information(gpointer user_data) +static void get_licensable_feature_information(gpointer user_data) { CtkManageGridLicense *ctk_manage_grid_license = CTK_MANAGE_GRID_LICENSE(user_data); nvmlGridLicensableFeatures_t *gridLicensableFeatures; @@ -1107,6 +1107,11 @@ static void get_licensed_feature_information(gpointer user_data) licensedFeatureCode = gridLicensableFeatures->gridLicensableFeatures[i].featureCode; break; } + else if (gridLicensableFeatures->gridLicensableFeatures[i].featureState == 0 && + gridLicensableFeatures->gridLicensableFeatures[i].featureCode == NVML_GRID_LICENSE_FEATURE_CODE_VWORKSTATION) + { + break; + } } nvfree(gridLicensableFeatures); } @@ -1558,7 +1563,7 @@ GtkWidget* ctk_manage_grid_license_new(CtrlTarget *target, gtk_box_set_spacing(GTK_BOX(ctk_manage_grid_license), 5); - get_licensed_feature_information(ctk_manage_grid_license); + get_licensable_feature_information(ctk_manage_grid_license); /* banner */ diff --git a/src/gtk+-2.x/ctkscale.c b/src/gtk+-2.x/ctkscale.c index 5ba439d..f44cf9e 100644 --- a/src/gtk+-2.x/ctkscale.c +++ b/src/gtk+-2.x/ctkscale.c @@ -298,7 +298,7 @@ GtkWidget* ctk_scale_new(GtkAdjustment *gtk_adjustment, gtk_scale_set_draw_value(GTK_SCALE(ctk_scale->gtk_scale), FALSE); - gtk_scale_set_digits(GTK_SCALE(ctk_scale->gtk_scale), 0); + gtk_scale_set_digits(GTK_SCALE(ctk_scale->gtk_scale), 6); gtk_box_pack_start(GTK_BOX(hbox), ctk_scale->gtk_scale, TRUE, TRUE, 3); diff --git a/src/gtk+-2.x/ctkvdpau.c b/src/gtk+-2.x/ctkvdpau.c index 58b756d..64f2d28 100644 --- a/src/gtk+-2.x/ctkvdpau.c +++ b/src/gtk+-2.x/ctkvdpau.c @@ -284,6 +284,12 @@ static const Desc ycbcr_types[] = { {"YUYV", VDP_YCBCR_FORMAT_YUYV, 0}, {"Y8U8V8A8", VDP_YCBCR_FORMAT_Y8U8V8A8, 0}, {"V8U8Y8A8", VDP_YCBCR_FORMAT_V8U8Y8A8, 0}, +#ifdef VDP_YCBCR_FORMAT_Y_UV_444 + {"Y_UV_444", VDP_YCBCR_FORMAT_Y_UV_444, 0}, + {"Y_U_V_444", VDP_YCBCR_FORMAT_Y_U_V_444, 0}, +#else +#warning "Update libvdpau to version 1.2" +#endif }; static const size_t ycbcr_type_count = sizeof(ycbcr_types)/sizeof(Desc); @@ -644,8 +650,8 @@ static int queryDecoderCaps(CtkVDPAU *ctk_vdpau, VdpDevice device, gtk_misc_set_alignment(GTK_MISC(label), 0.0f, 0.5f); gtk_table_attach(GTK_TABLE(table), label, 4, 5, count+3, count+4, GTK_FILL, GTK_FILL | GTK_EXPAND, 5, 0); + count++; } - count++; } return 0; } /* queryDecoderCaps() */ diff --git a/src/jansson/dump.c b/src/jansson/dump.c index 7eddd5a..89802c6 100644 --- a/src/jansson/dump.c +++ b/src/jansson/dump.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org> + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -9,22 +9,30 @@ #define _GNU_SOURCE #endif +#include "jansson_private.h" + #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif #include "jansson.h" -#include "jansson_private.h" #include "strbuffer.h" #include "utf.h" #define MAX_INTEGER_STR_LENGTH 100 #define MAX_REAL_STR_LENGTH 100 -struct object_key { - size_t serial; - const char *key; +#define FLAGS_TO_INDENT(f) ((f) & 0x1F) +#define FLAGS_TO_PRECISION(f) (((f) >> 11) & 0x1F) + +struct buffer { + const size_t size; + size_t used; + char *data; }; static int dump_to_strbuffer(const char *buffer, size_t size, void *data) @@ -32,6 +40,17 @@ static int dump_to_strbuffer(const char *buffer, size_t size, void *data) return strbuffer_append_bytes((strbuffer_t *)data, buffer, size); } +static int dump_to_buffer(const char *buffer, size_t size, void *data) +{ + struct buffer *buf = (struct buffer *)data; + + if(buf->used + size <= buf->size) + memcpy(&buf->data[buf->used], buffer, size); + + buf->used += size; + return 0; +} + static int dump_to_file(const char *buffer, size_t size, void *data) { FILE *dest = (FILE *)data; @@ -40,22 +59,36 @@ static int dump_to_file(const char *buffer, size_t size, void *data) return 0; } +static int dump_to_fd(const char *buffer, size_t size, void *data) +{ +#ifdef HAVE_UNISTD_H + int *dest = (int *)data; + if(write(*dest, buffer, size) == (ssize_t)size) + return 0; +#endif + return -1; +} + /* 32 spaces (the maximum indentation size) */ static const char whitespace[] = " "; static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data) { - if(JSON_INDENT(flags) > 0) + if(FLAGS_TO_INDENT(flags) > 0) { - int i, ws_count = JSON_INDENT(flags); + unsigned int ws_count = FLAGS_TO_INDENT(flags), n_spaces = depth * ws_count; if(dump("\n", 1, data)) return -1; - for(i = 0; i < depth; i++) + while(n_spaces > 0) { - if(dump(whitespace, ws_count, data)) + int cur_n = n_spaces < sizeof whitespace - 1 ? n_spaces : sizeof whitespace - 1; + + if(dump(whitespace, cur_n, data)) return -1; + + n_spaces -= cur_n; } } else if(space && !(flags & JSON_COMPACT)) @@ -68,7 +101,7 @@ static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t static int dump_string(const char *str, size_t len, json_dump_callback_t dump, void *data, size_t flags) { const char *pos, *end, *lim; - int32_t codepoint; + int32_t codepoint = 0; if(dump("\"", 1, data)) return -1; @@ -127,7 +160,7 @@ static int dump_string(const char *str, size_t len, json_dump_callback_t dump, v /* codepoint is in BMP */ if(codepoint < 0x10000) { - sprintf(seq, "\\u%04X", codepoint); + snprintf(seq, sizeof(seq), "\\u%04X", (unsigned int)codepoint); length = 6; } @@ -140,7 +173,7 @@ static int dump_string(const char *str, size_t len, json_dump_callback_t dump, v first = 0xD800 | ((codepoint & 0xffc00) >> 10); last = 0xDC00 | (codepoint & 0x003ff); - sprintf(seq, "\\u%04X\\u%04X", first, last); + snprintf(seq, sizeof(seq), "\\u%04X\\u%04X", (unsigned int)first, (unsigned int)last); length = 12; } @@ -158,23 +191,27 @@ static int dump_string(const char *str, size_t len, json_dump_callback_t dump, v return dump("\"", 1, data); } -static int object_key_compare_keys(const void *key1, const void *key2) +static int compare_keys(const void *key1, const void *key2) { - return strcmp(((const struct object_key *)key1)->key, - ((const struct object_key *)key2)->key); + return strcmp(*(const char **)key1, *(const char **)key2); } -static int object_key_compare_serials(const void *key1, const void *key2) +static int loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size) { - size_t a = ((const struct object_key *)key1)->serial; - size_t b = ((const struct object_key *)key2)->serial; + snprintf(key, key_size, "%p", json); + if (hashtable_get(parents, key)) + return -1; - return a < b ? -1 : a == b ? 0 : 1; + return hashtable_set(parents, key, json_null()); } static int do_dump(const json_t *json, size_t flags, int depth, - json_dump_callback_t dump, void *data) + hashtable_t *parents, json_dump_callback_t dump, void *data) { + int embed = flags & JSON_EMBED; + + flags &= ~JSON_EMBED; + if(!json) return -1; @@ -208,7 +245,8 @@ static int do_dump(const json_t *json, size_t flags, int depth, int size; double value = json_real_value(json); - size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value); + size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value, + FLAGS_TO_PRECISION(flags)); if(size < 0) return -1; @@ -220,59 +258,55 @@ static int do_dump(const json_t *json, size_t flags, int depth, case JSON_ARRAY: { - int i; - int n; - json_array_t *array; + size_t n; + size_t i; + /* Space for "0x", double the sizeof a pointer for the hex and a terminator. */ + char key[2 + (sizeof(json) * 2) + 1]; /* detect circular references */ - array = json_to_array(json); - if(array->visited) - goto array_error; - array->visited = 1; + if (loop_check(parents, json, key, sizeof(key))) + return -1; n = json_array_size(json); - if(dump("[", 1, data)) - goto array_error; + if(!embed && dump("[", 1, data)) + return -1; if(n == 0) { - array->visited = 0; - return dump("]", 1, data); + hashtable_del(parents, key); + return embed ? 0 : dump("]", 1, data); } if(dump_indent(flags, depth + 1, 0, dump, data)) - goto array_error; + return -1; for(i = 0; i < n; ++i) { if(do_dump(json_array_get(json, i), flags, depth + 1, - dump, data)) - goto array_error; + parents, dump, data)) + return -1; if(i < n - 1) { if(dump(",", 1, data) || dump_indent(flags, depth + 1, 1, dump, data)) - goto array_error; + return -1; } else { if(dump_indent(flags, depth, 0, dump, data)) - goto array_error; + return -1; } } - array->visited = 0; - return dump("]", 1, data); - - array_error: - array->visited = 0; - return -1; + hashtable_del(parents, key); + return embed ? 0 : dump("]", 1, data); } case JSON_OBJECT: { - json_object_t *object; void *iter; const char *separator; int separator_length; + /* Space for "0x", double the sizeof a pointer for the hex and a terminator. */ + char loop_key[2 + (sizeof(json) * 2) + 1]; if(flags & JSON_COMPACT) { separator = ":"; @@ -284,65 +318,56 @@ static int do_dump(const json_t *json, size_t flags, int depth, } /* detect circular references */ - object = json_to_object(json); - if(object->visited) - goto object_error; - object->visited = 1; + if (loop_check(parents, json, loop_key, sizeof(loop_key))) + return -1; iter = json_object_iter((json_t *)json); - if(dump("{", 1, data)) - goto object_error; + if(!embed && dump("{", 1, data)) + return -1; if(!iter) { - object->visited = 0; - return dump("}", 1, data); + hashtable_del(parents, loop_key); + return embed ? 0 : dump("}", 1, data); } if(dump_indent(flags, depth + 1, 0, dump, data)) - goto object_error; + return -1; - if(flags & JSON_SORT_KEYS || flags & JSON_PRESERVE_ORDER) + if(flags & JSON_SORT_KEYS) { - struct object_key *keys; + const char **keys; size_t size, i; - int (*cmp_func)(const void *, const void *); size = json_object_size(json); - keys = jsonp_malloc(size * sizeof(struct object_key)); + keys = jsonp_malloc(size * sizeof(const char *)); if(!keys) - goto object_error; + return -1; i = 0; while(iter) { - keys[i].serial = hashtable_iter_serial(iter); - keys[i].key = json_object_iter_key(iter); + keys[i] = json_object_iter_key(iter); iter = json_object_iter_next((json_t *)json, iter); i++; } assert(i == size); - if(flags & JSON_SORT_KEYS) - cmp_func = object_key_compare_keys; - else - cmp_func = object_key_compare_serials; - - qsort(keys, size, sizeof(struct object_key), cmp_func); + qsort(keys, size, sizeof(const char *), compare_keys); for(i = 0; i < size; i++) { const char *key; json_t *value; - key = keys[i].key; + key = keys[i]; value = json_object_get(json, key); assert(value); dump_string(key, strlen(key), dump, data, flags); if(dump(separator, separator_length, data) || - do_dump(value, flags, depth + 1, dump, data)) + do_dump(value, flags, depth + 1, parents, dump, data)) { jsonp_free(keys); - goto object_error; + return -1; } if(i < size - 1) @@ -351,7 +376,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, dump_indent(flags, depth + 1, 1, dump, data)) { jsonp_free(keys); - goto object_error; + return -1; } } else @@ -359,7 +384,7 @@ static int do_dump(const json_t *json, size_t flags, int depth, if(dump_indent(flags, depth, 0, dump, data)) { jsonp_free(keys); - goto object_error; + return -1; } } } @@ -378,31 +403,27 @@ static int do_dump(const json_t *json, size_t flags, int depth, dump_string(key, strlen(key), dump, data, flags); if(dump(separator, separator_length, data) || do_dump(json_object_iter_value(iter), flags, depth + 1, - dump, data)) - goto object_error; + parents, dump, data)) + return -1; if(next) { if(dump(",", 1, data) || dump_indent(flags, depth + 1, 1, dump, data)) - goto object_error; + return -1; } else { if(dump_indent(flags, depth, 0, dump, data)) - goto object_error; + return -1; } iter = next; } } - object->visited = 0; - return dump("}", 1, data); - - object_error: - object->visited = 0; - return -1; + hashtable_del(parents, loop_key); + return embed ? 0 : dump("}", 1, data); } default: @@ -428,11 +449,26 @@ char *json_dumps(const json_t *json, size_t flags) return result; } +size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags) +{ + struct buffer buf = { size, 0, buffer }; + + if(json_dump_callback(json, dump_to_buffer, (void *)&buf, flags)) + return 0; + + return buf.used; +} + int json_dumpf(const json_t *json, FILE *output, size_t flags) { return json_dump_callback(json, dump_to_file, (void *)output, flags); } +int json_dumpfd(const json_t *json, int output, size_t flags) +{ + return json_dump_callback(json, dump_to_fd, (void *)&output, flags); +} + int json_dump_file(const json_t *json, const char *path, size_t flags) { int result; @@ -443,16 +479,26 @@ int json_dump_file(const json_t *json, const char *path, size_t flags) result = json_dumpf(json, output, flags); - fclose(output); + if(fclose(output) != 0) + return -1; + return result; } int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags) { + int res; + hashtable_t parents_set; + if(!(flags & JSON_ENCODE_ANY)) { if(!json_is_array(json) && !json_is_object(json)) return -1; } - return do_dump(json, flags, 0, callback, data); + if (hashtable_init(&parents_set)) + return -1; + res = do_dump(json, flags, 0, &parents_set, callback, data); + hashtable_close(&parents_set); + + return res; } diff --git a/src/jansson/error.c b/src/jansson/error.c index a544a59..f5da6b9 100644 --- a/src/jansson/error.c +++ b/src/jansson/error.c @@ -25,26 +25,28 @@ void jsonp_error_set_source(json_error_t *error, const char *source) length = strlen(source); if(length < JSON_ERROR_SOURCE_LENGTH) - strcpy(error->source, source); + strncpy(error->source, source, length + 1); else { size_t extra = length - JSON_ERROR_SOURCE_LENGTH + 4; - strcpy(error->source, "..."); - strcpy(error->source + 3, source + extra); + memcpy(error->source, "...", 3); + strncpy(error->source + 3, source + extra, length - extra + 1); } } void jsonp_error_set(json_error_t *error, int line, int column, - size_t position, const char *msg, ...) + size_t position, enum json_error_code code, + const char *msg, ...) { va_list ap; va_start(ap, msg); - jsonp_error_vset(error, line, column, position, msg, ap); + jsonp_error_vset(error, line, column, position, code, msg, ap); va_end(ap); } void jsonp_error_vset(json_error_t *error, int line, int column, - size_t position, const char *msg, va_list ap) + size_t position, enum json_error_code code, + const char *msg, va_list ap) { if(!error) return; @@ -56,8 +58,9 @@ void jsonp_error_vset(json_error_t *error, int line, int column, error->line = line; error->column = column; - error->position = position; + error->position = (int)position; - vsnprintf(error->text, JSON_ERROR_TEXT_LENGTH, msg, ap); - error->text[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; + vsnprintf(error->text, JSON_ERROR_TEXT_LENGTH - 1, msg, ap); + error->text[JSON_ERROR_TEXT_LENGTH - 2] = '\0'; + error->text[JSON_ERROR_TEXT_LENGTH - 1] = code; } diff --git a/src/jansson/hashtable.c b/src/jansson/hashtable.c index 4c4b565..c819319 100644 --- a/src/jansson/hashtable.c +++ b/src/jansson/hashtable.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org> + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> * * This library is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -20,6 +20,10 @@ #include "jansson_private.h" /* for container_of() */ #include "hashtable.h" +#ifndef INITIAL_HASHTABLE_ORDER +#define INITIAL_HASHTABLE_ORDER 3 +#endif + typedef struct hashtable_list list_t; typedef struct hashtable_pair pair_t; typedef struct hashtable_bucket bucket_t; @@ -30,6 +34,7 @@ extern volatile uint32_t hashtable_seed; #include "lookup3.h" #define list_to_pair(list_) container_of(list_, pair_t, list) +#define ordered_list_to_pair(list_) container_of(list_, pair_t, ordered_list) #define hash_str(key) ((size_t)hashlittle((key), strlen(key), hashtable_seed)) static JSON_INLINE void list_init(list_t *list) @@ -122,6 +127,7 @@ static int hashtable_do_del(hashtable_t *hashtable, bucket->last = pair->list.prev; list_remove(&pair->list); + list_remove(&pair->ordered_list); json_decref(pair->value); jsonp_free(pair); @@ -148,17 +154,20 @@ static int hashtable_do_rehash(hashtable_t *hashtable) { list_t *list, *next; pair_t *pair; - size_t i, index, new_size; + size_t i, index, new_size, new_order; + struct hashtable_bucket *new_buckets; - jsonp_free(hashtable->buckets); + new_order = hashtable->order + 1; + new_size = hashsize(new_order); - hashtable->order++; - new_size = hashsize(hashtable->order); - - hashtable->buckets = jsonp_malloc(new_size * sizeof(bucket_t)); - if(!hashtable->buckets) + new_buckets = jsonp_malloc(new_size * sizeof(bucket_t)); + if(!new_buckets) return -1; + jsonp_free(hashtable->buckets); + hashtable->buckets = new_buckets; + hashtable->order = new_order; + for(i = 0; i < hashsize(hashtable->order); i++) { hashtable->buckets[i].first = hashtable->buckets[i].last = @@ -184,12 +193,13 @@ int hashtable_init(hashtable_t *hashtable) size_t i; hashtable->size = 0; - hashtable->order = 3; + hashtable->order = INITIAL_HASHTABLE_ORDER; hashtable->buckets = jsonp_malloc(hashsize(hashtable->order) * sizeof(bucket_t)); if(!hashtable->buckets) return -1; list_init(&hashtable->list); + list_init(&hashtable->ordered_list); for(i = 0; i < hashsize(hashtable->order); i++) { @@ -206,9 +216,7 @@ void hashtable_close(hashtable_t *hashtable) jsonp_free(hashtable->buckets); } -int hashtable_set(hashtable_t *hashtable, - const char *key, size_t serial, - json_t *value) +int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value) { pair_t *pair; bucket_t *bucket; @@ -246,12 +254,13 @@ int hashtable_set(hashtable_t *hashtable, return -1; pair->hash = hash; - pair->serial = serial; - strcpy(pair->key, key); + strncpy(pair->key, key, len + 1); pair->value = value; list_init(&pair->list); + list_init(&pair->ordered_list); insert_to_bucket(hashtable, bucket, &pair->list); + list_insert(&hashtable->ordered_list, &pair->ordered_list); hashtable->size++; } @@ -293,12 +302,13 @@ void hashtable_clear(hashtable_t *hashtable) } list_init(&hashtable->list); + list_init(&hashtable->ordered_list); hashtable->size = 0; } void *hashtable_iter(hashtable_t *hashtable) { - return hashtable_iter_next(hashtable, &hashtable->list); + return hashtable_iter_next(hashtable, &hashtable->ordered_list); } void *hashtable_iter_at(hashtable_t *hashtable, const char *key) @@ -314,38 +324,32 @@ void *hashtable_iter_at(hashtable_t *hashtable, const char *key) if(!pair) return NULL; - return &pair->list; + return &pair->ordered_list; } void *hashtable_iter_next(hashtable_t *hashtable, void *iter) { list_t *list = (list_t *)iter; - if(list->next == &hashtable->list) + if(list->next == &hashtable->ordered_list) return NULL; return list->next; } void *hashtable_iter_key(void *iter) { - pair_t *pair = list_to_pair((list_t *)iter); + pair_t *pair = ordered_list_to_pair((list_t *)iter); return pair->key; } -size_t hashtable_iter_serial(void *iter) -{ - pair_t *pair = list_to_pair((list_t *)iter); - return pair->serial; -} - void *hashtable_iter_value(void *iter) { - pair_t *pair = list_to_pair((list_t *)iter); + pair_t *pair = ordered_list_to_pair((list_t *)iter); return pair->value; } void hashtable_iter_set(void *iter, json_t *value) { - pair_t *pair = list_to_pair((list_t *)iter); + pair_t *pair = ordered_list_to_pair((list_t *)iter); json_decref(pair->value); pair->value = value; diff --git a/src/jansson/hashtable.h b/src/jansson/hashtable.h index f54c3fe..c112834 100644 --- a/src/jansson/hashtable.h +++ b/src/jansson/hashtable.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org> + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> * * This library is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -8,6 +8,9 @@ #ifndef HASHTABLE_H #define HASHTABLE_H +#include <stdlib.h> +#include "jansson.h" + struct hashtable_list { struct hashtable_list *prev; struct hashtable_list *next; @@ -17,10 +20,10 @@ struct hashtable_list { key-value pair. In this case, it just encodes some extra data, too */ struct hashtable_pair { - size_t hash; struct hashtable_list list; + struct hashtable_list ordered_list; + size_t hash; json_t *value; - size_t serial; char key[1]; }; @@ -34,11 +37,12 @@ typedef struct hashtable { struct hashtable_bucket *buckets; size_t order; /* hashtable has pow(2, order) buckets */ struct hashtable_list list; + struct hashtable_list ordered_list; } hashtable_t; #define hashtable_key_to_iter(key_) \ - (&(container_of(key_, struct hashtable_pair, key)->list)) + (&(container_of(key_, struct hashtable_pair, key)->ordered_list)) /** @@ -51,7 +55,7 @@ typedef struct hashtable { * * Returns 0 on success, -1 on error (out of memory). */ -int hashtable_init(hashtable_t *hashtable); +int hashtable_init(hashtable_t *hashtable) JANSSON_ATTRS(warn_unused_result); /** * hashtable_close - Release all resources used by a hashtable object @@ -77,9 +81,7 @@ void hashtable_close(hashtable_t *hashtable); * * Returns 0 on success, -1 on failure (out of memory). */ -int hashtable_set(hashtable_t *hashtable, - const char *key, size_t serial, - json_t *value); +int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value); /** * hashtable_get - Get a value associated with a key @@ -157,13 +159,6 @@ void *hashtable_iter_next(hashtable_t *hashtable, void *iter); void *hashtable_iter_key(void *iter); /** - * hashtable_iter_serial - Retrieve the serial number pointed to by an iterator - * - * @iter: The iterator - */ -size_t hashtable_iter_serial(void *iter); - -/** * hashtable_iter_value - Retrieve the value pointed by an iterator * * @iter: The iterator diff --git a/src/jansson/hashtable_seed.c b/src/jansson/hashtable_seed.c index 751e0e3..540358a 100644 --- a/src/jansson/hashtable_seed.c +++ b/src/jansson/hashtable_seed.c @@ -164,16 +164,16 @@ static int seed_from_timestamp_and_pid(uint32_t *seed) { } static uint32_t generate_seed() { - uint32_t seed; + uint32_t seed = 0; int done = 0; #if !defined(_WIN32) && defined(USE_URANDOM) - if (!done && seed_from_urandom(&seed) == 0) + if (seed_from_urandom(&seed) == 0) done = 1; #endif #if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI) - if (!done && seed_from_windows_cryptoapi(&seed) == 0) + if (seed_from_windows_cryptoapi(&seed) == 0) done = 1; #endif diff --git a/src/jansson/jansson.h b/src/jansson/jansson.h index 85215f4..e4e73e2 100644 --- a/src/jansson/jansson.h +++ b/src/jansson/jansson.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org> + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -12,7 +12,7 @@ #include <stdlib.h> /* for size_t */ #include <stdarg.h> -#include <jansson_config.h> +#include "jansson_config.h" #ifdef __cplusplus extern "C" { @@ -21,11 +21,11 @@ extern "C" { /* version */ #define JANSSON_MAJOR_VERSION 2 -#define JANSSON_MINOR_VERSION 6 +#define JANSSON_MINOR_VERSION 12 #define JANSSON_MICRO_VERSION 0 /* Micro version is omitted if it's 0 */ -#define JANSSON_VERSION "2.6" +#define JANSSON_VERSION "2.12" /* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */ @@ -33,6 +33,17 @@ extern "C" { (JANSSON_MINOR_VERSION << 8) | \ (JANSSON_MICRO_VERSION << 0)) +/* If __atomic or __sync builtins are available the library is thread + * safe for all read-only functions plus reference counting. */ +#if JSON_HAVE_ATOMIC_BUILTINS || JSON_HAVE_SYNC_BUILTINS +#define JANSSON_THREAD_SAFE_REFCOUNT 1 +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define JANSSON_ATTRS(...) __attribute__((__VA_ARGS__)) +#else +#define JANSSON_ATTRS(...) +#endif /* types */ @@ -49,7 +60,7 @@ typedef enum { typedef struct json_t { json_type type; - size_t refcount; + volatile size_t refcount; } json_t; #ifndef JANSSON_USING_CMAKE /* disabled if using cmake */ @@ -94,11 +105,23 @@ json_t *json_false(void); #define json_boolean(val) ((val) ? json_true() : json_false()) json_t *json_null(void); +/* do not call JSON_INTERNAL_INCREF or JSON_INTERNAL_DECREF directly */ +#if JSON_HAVE_ATOMIC_BUILTINS +#define JSON_INTERNAL_INCREF(json) __atomic_add_fetch(&json->refcount, 1, __ATOMIC_ACQUIRE) +#define JSON_INTERNAL_DECREF(json) __atomic_sub_fetch(&json->refcount, 1, __ATOMIC_RELEASE) +#elif JSON_HAVE_SYNC_BUILTINS +#define JSON_INTERNAL_INCREF(json) __sync_add_and_fetch(&json->refcount, 1) +#define JSON_INTERNAL_DECREF(json) __sync_sub_and_fetch(&json->refcount, 1) +#else +#define JSON_INTERNAL_INCREF(json) (++json->refcount) +#define JSON_INTERNAL_DECREF(json) (--json->refcount) +#endif + static JSON_INLINE json_t *json_incref(json_t *json) { if(json && json->refcount != (size_t)-1) - ++json->refcount; + JSON_INTERNAL_INCREF(json); return json; } @@ -108,17 +131,30 @@ void json_delete(json_t *json); static JSON_INLINE void json_decref(json_t *json) { - if(json && json->refcount != (size_t)-1 && --json->refcount == 0) + if(json && json->refcount != (size_t)-1 && JSON_INTERNAL_DECREF(json) == 0) json_delete(json); } +#if defined(__GNUC__) || defined(__clang__) +static JSON_INLINE +void json_decrefp(json_t **json) +{ + if(json) { + json_decref(*json); + *json = NULL; + } +} + +#define json_auto_t json_t __attribute__((cleanup(json_decrefp))) +#endif + /* error reporting */ #define JSON_ERROR_TEXT_LENGTH 160 #define JSON_ERROR_SOURCE_LENGTH 80 -typedef struct { +typedef struct json_error_t { int line; int column; int position; @@ -126,12 +162,36 @@ typedef struct { char text[JSON_ERROR_TEXT_LENGTH]; } json_error_t; +enum json_error_code { + json_error_unknown, + json_error_out_of_memory, + json_error_stack_overflow, + json_error_cannot_open_file, + json_error_invalid_argument, + json_error_invalid_utf8, + json_error_premature_end_of_input, + json_error_end_of_input_expected, + json_error_invalid_syntax, + json_error_invalid_format, + json_error_wrong_type, + json_error_null_character, + json_error_null_value, + json_error_null_byte_in_key, + json_error_duplicate_key, + json_error_numeric_overflow, + json_error_item_not_found, + json_error_index_out_of_range +}; + +static JSON_INLINE enum json_error_code json_error_code(const json_error_t *e) { + return (enum json_error_code)e->text[JSON_ERROR_TEXT_LENGTH - 1]; +} /* getters, setters, manipulation */ void json_object_seed(size_t seed); size_t json_object_size(const json_t *object); -json_t *json_object_get(const json_t *object, const char *key); +json_t *json_object_get(const json_t *object, const char *key) JANSSON_ATTRS(warn_unused_result); int json_object_set_new(json_t *object, const char *key, json_t *value); int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value); int json_object_del(json_t *object, const char *key); @@ -152,6 +212,13 @@ int json_object_iter_set_new(json_t *object, void *iter, json_t *value); key && (value = json_object_iter_value(json_object_key_to_iter(key))); \ key = json_object_iter_key(json_object_iter_next(object, json_object_key_to_iter(key)))) +#define json_object_foreach_safe(object, n, key, value) \ + for(key = json_object_iter_key(json_object_iter(object)), \ + n = json_object_iter_next(object, json_object_key_to_iter(key)); \ + key && (value = json_object_iter_value(json_object_key_to_iter(key))); \ + key = json_object_iter_key(n), \ + n = json_object_iter_next(object, json_object_key_to_iter(key))) + #define json_array_foreach(array, index, value) \ for(index = 0; \ index < json_array_size(array) && (value = json_array_get(array, index)); \ @@ -176,7 +243,7 @@ int json_object_iter_set(json_t *object, void *iter, json_t *value) } size_t json_array_size(const json_t *array); -json_t *json_array_get(const json_t *array, size_t index); +json_t *json_array_get(const json_t *array, size_t index) JANSSON_ATTRS(warn_unused_result); int json_array_set_new(json_t *array, size_t index, json_t *value); int json_array_append_new(json_t *array, json_t *value); int json_array_insert_new(json_t *array, size_t index, json_t *value); @@ -217,9 +284,9 @@ int json_real_set(json_t *real, double value); /* pack, unpack */ -json_t *json_pack(const char *fmt, ...); -json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...); -json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap); +json_t *json_pack(const char *fmt, ...) JANSSON_ATTRS(warn_unused_result); +json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) JANSSON_ATTRS(warn_unused_result); +json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap) JANSSON_ATTRS(warn_unused_result); #define JSON_VALIDATE_ONLY 0x1 #define JSON_STRICT 0x2 @@ -228,16 +295,21 @@ int json_unpack(json_t *root, const char *fmt, ...); int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...); int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, va_list ap); +/* sprintf */ + +json_t *json_sprintf(const char *fmt, ...) JANSSON_ATTRS(warn_unused_result, format(printf, 1, 2)); +json_t *json_vsprintf(const char *fmt, va_list ap) JANSSON_ATTRS(warn_unused_result, format(printf, 1, 0)); + /* equality */ -int json_equal(json_t *value1, json_t *value2); +int json_equal(const json_t *value1, const json_t *value2); /* copying */ -json_t *json_copy(json_t *value); -json_t *json_deep_copy(const json_t *value); +json_t *json_copy(json_t *value) JANSSON_ATTRS(warn_unused_result); +json_t *json_deep_copy(const json_t *value) JANSSON_ATTRS(warn_unused_result); /* decoding */ @@ -250,27 +322,33 @@ json_t *json_deep_copy(const json_t *value); typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data); -json_t *json_loads(const char *input, size_t flags, json_error_t *error); -json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error); -json_t *json_loadf(FILE *input, size_t flags, json_error_t *error); -json_t *json_load_file(const char *path, size_t flags, json_error_t *error); -json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error); +json_t *json_loads(const char *input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); +json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); +json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); +json_t *json_loadfd(int input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); +json_t *json_load_file(const char *path, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); +json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); /* encoding */ -#define JSON_INDENT(n) (n & 0x1F) -#define JSON_COMPACT 0x20 -#define JSON_ENSURE_ASCII 0x40 -#define JSON_SORT_KEYS 0x80 -#define JSON_PRESERVE_ORDER 0x100 -#define JSON_ENCODE_ANY 0x200 -#define JSON_ESCAPE_SLASH 0x400 +#define JSON_MAX_INDENT 0x1F +#define JSON_INDENT(n) ((n) & JSON_MAX_INDENT) +#define JSON_COMPACT 0x20 +#define JSON_ENSURE_ASCII 0x40 +#define JSON_SORT_KEYS 0x80 +#define JSON_PRESERVE_ORDER 0x100 +#define JSON_ENCODE_ANY 0x200 +#define JSON_ESCAPE_SLASH 0x400 +#define JSON_REAL_PRECISION(n) (((n) & 0x1F) << 11) +#define JSON_EMBED 0x10000 typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data); -char *json_dumps(const json_t *json, size_t flags); +char *json_dumps(const json_t *json, size_t flags) JANSSON_ATTRS(warn_unused_result); +size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags); int json_dumpf(const json_t *json, FILE *output, size_t flags); +int json_dumpfd(const json_t *json, int output, size_t flags); int json_dump_file(const json_t *json, const char *path, size_t flags); int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags); @@ -280,6 +358,7 @@ typedef void *(*json_malloc_t)(size_t); typedef void (*json_free_t)(void *); void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn); +void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn); #ifdef __cplusplus } diff --git a/src/jansson/jansson_config.h b/src/jansson/jansson_config.h index 31ad6b3..b397f20 100644 --- a/src/jansson/jansson_config.h +++ b/src/jansson/jansson_config.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2010-2014 Petri Lehtinen <petri@digip.org> + * Copyright (c) 2010-2016 Petri Lehtinen <petri@digip.org> * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -59,6 +59,16 @@ /* If locale.h and localeconv() are available, define to 1, otherwise to 0. */ #define JSON_HAVE_LOCALECONV 1 +/* If __atomic builtins are available they will be used to manage + reference counts of json_t. */ +#define JSON_HAVE_ATOMIC_BUILTINS 0 +/* If __atomic builtins are not available we try using __sync builtins + to manage reference counts of json_t. */ +#define JSON_HAVE_SYNC_BUILTINS 0 + +/* Maximum recursion depth for parsing JSON input. + This limits the depth of e.g. array-within-array constructions. */ +#define JSON_PARSER_MAX_DEPTH 2048 #endif diff --git a/src/jansson/jansson_private.h b/src/jansson/jansson_private.h index c6f437c..bf86c57 100644 --- a/src/jansson/jansson_private.h +++ b/src/jansson/jansson_private.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org> + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -8,6 +8,7 @@ #ifndef JANSSON_PRIVATE_H #define JANSSON_PRIVATE_H +#include "jansson_private_config.h" #include <stddef.h> #include "jansson.h" #include "hashtable.h" @@ -34,8 +35,6 @@ typedef struct { json_t json; hashtable_t hashtable; - size_t serial; - int visited; } json_object_t; typedef struct { @@ -43,7 +42,6 @@ typedef struct { size_t size; size_t entries; json_t **table; - int visited; } json_array_t; typedef struct { @@ -75,25 +73,37 @@ json_t *jsonp_stringn_nocheck_own(const char *value, size_t len); void jsonp_error_init(json_error_t *error, const char *source); void jsonp_error_set_source(json_error_t *error, const char *source); void jsonp_error_set(json_error_t *error, int line, int column, - size_t position, const char *msg, ...); + size_t position, enum json_error_code code, + const char *msg, ...); void jsonp_error_vset(json_error_t *error, int line, int column, - size_t position, const char *msg, va_list ap); + size_t position, enum json_error_code code, + const char *msg, va_list ap); /* Locale independent string<->double conversions */ int jsonp_strtod(strbuffer_t *strbuffer, double *out); -int jsonp_dtostr(char *buffer, size_t size, double value); +int jsonp_dtostr(char *buffer, size_t size, double value, int prec); /* Wrappers for custom memory functions */ -void* jsonp_malloc(size_t size); +void* jsonp_malloc(size_t size) JANSSON_ATTRS(warn_unused_result); void jsonp_free(void *ptr); -char *jsonp_strndup(const char *str, size_t length); -char *jsonp_strdup(const char *str); -char *jsonp_strndup(const char *str, size_t len); +char *jsonp_strndup(const char *str, size_t length) JANSSON_ATTRS(warn_unused_result); +char *jsonp_strdup(const char *str) JANSSON_ATTRS(warn_unused_result); +char *jsonp_strndup(const char *str, size_t len) JANSSON_ATTRS(warn_unused_result); + /* Windows compatibility */ -#ifdef _WIN32 -#define snprintf _snprintf -#define vsnprintf _vsnprintf +#if defined(_WIN32) || defined(WIN32) +# if defined(_MSC_VER) /* MS compiller */ +# if (_MSC_VER < 1900) && !defined(snprintf) /* snprintf not defined yet & not introduced */ +# define snprintf _snprintf +# endif +# if (_MSC_VER < 1500) && !defined(vsnprintf) /* vsnprintf not defined yet & not introduced */ +# define vsnprintf(b,c,f,a) _vsnprintf(b,c,f,a) +# endif +# else /* Other Windows compiller, old definition */ +# define snprintf _snprintf +# define vsnprintf _vsnprintf +# endif #endif #endif diff --git a/src/jansson/jansson_private_config.h b/src/jansson/jansson_private_config.h index cbff15e..6b51bc0 100644 --- a/src/jansson/jansson_private_config.h +++ b/src/jansson/jansson_private_config.h @@ -39,19 +39,23 @@ # define uint32_t uint32_t #endif -#define HAVE_SSIZE_T 1 +#define HAVE_UINT16_T 1 +#ifndef HAVE_UINT16_T +# define uint16_t uint16_t +#endif -#ifndef HAVE_SSIZE_T -# define ssize_t +#define HAVE_UINT8_T 1 +#ifndef HAVE_UINT8_T +# define uint8_t uint8_t #endif -#define HAVE_SNPRINTF 1 +#define HAVE_SSIZE_T 1 -#ifndef HAVE_SNPRINTF -# define snprintf snprintf +#ifndef HAVE_SSIZE_T +# define ssize_t #endif -/* #undef HAVE_VSNPRINTF */ - #define USE_URANDOM 1 #define USE_WINDOWS_CRYPTOAPI 1 + +#define INITIAL_HASHTABLE_ORDER 3 diff --git a/src/jansson/load.c b/src/jansson/load.c index 56c8ee3..8700919 100644 --- a/src/jansson/load.c +++ b/src/jansson/load.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org> + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -9,15 +9,19 @@ #define _GNU_SOURCE #endif +#include "jansson_private.h" + #include <errno.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h> +#ifdef HAVE_UNISTD_H +#include <unistd.h> +#endif #include "jansson.h" -#include "jansson_private.h" #include "strbuffer.h" #include "utf.h" @@ -61,6 +65,8 @@ typedef struct { typedef struct { stream_t stream; strbuffer_t saved_text; + size_t flags; + size_t depth; int token; union { struct { @@ -78,6 +84,7 @@ typedef struct { /*** error reporting ***/ static void error_set(json_error_t *error, const lex_t *lex, + enum json_error_code code, const char *msg, ...) { va_list ap; @@ -115,6 +122,10 @@ static void error_set(json_error_t *error, const lex_t *lex, } else { + if(code == json_error_invalid_syntax) { + /* More specific error code for premature end of file. */ + code = json_error_premature_end_of_input; + } if(lex->stream.state == STREAM_STATE_ERROR) { /* No context for UTF-8 decoding errors */ result = msg_text; @@ -128,7 +139,7 @@ static void error_set(json_error_t *error, const lex_t *lex, } } - jsonp_error_set(error, line, col, pos, "%s", result); + jsonp_error_set(error, line, col, pos, code, "%s", result); } @@ -169,7 +180,7 @@ static int stream_get(stream_t *stream, json_error_t *error) if(0x80 <= c && c <= 0xFF) { /* multi-byte UTF-8 sequence */ - int i, count; + size_t i, count; count = utf8_check_first(c); if(!count) @@ -207,7 +218,7 @@ static int stream_get(stream_t *stream, json_error_t *error) out: stream->state = STREAM_STATE_ERROR; - error_set(error, stream_to_lex(stream), "unable to decode byte 0x%x", c); + error_set(error, stream_to_lex(stream), json_error_invalid_utf8, "unable to decode byte 0x%x", c); return STREAM_STATE_ERROR; } @@ -265,7 +276,7 @@ static void lex_unget_unsave(lex_t *lex, int c) #endif stream_unget(&lex->stream, c); #ifndef NDEBUG - d = + d = #endif strbuffer_pop(&lex->saved_text); assert(c == d); @@ -330,7 +341,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error) goto out; else if(c == STREAM_STATE_EOF) { - error_set(error, lex, "premature end of input"); + error_set(error, lex, json_error_premature_end_of_input, "premature end of input"); goto out; } @@ -338,9 +349,9 @@ static void lex_scan_string(lex_t *lex, json_error_t *error) /* control character */ lex_unget_unsave(lex, c); if(c == '\n') - error_set(error, lex, "unexpected newline", c); + error_set(error, lex, json_error_invalid_syntax, "unexpected newline"); else - error_set(error, lex, "control character 0x%x", c); + error_set(error, lex, json_error_invalid_syntax, "control character 0x%x", c); goto out; } @@ -350,7 +361,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error) c = lex_get_save(lex, error); for(i = 0; i < 4; i++) { if(!l_isxdigit(c)) { - error_set(error, lex, "invalid escape"); + error_set(error, lex, json_error_invalid_syntax, "invalid escape"); goto out; } c = lex_get_save(lex, error); @@ -360,7 +371,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error) c == 'f' || c == 'n' || c == 'r' || c == 't') c = lex_get_save(lex, error); else { - error_set(error, lex, "invalid escape"); + error_set(error, lex, json_error_invalid_syntax, "invalid escape"); goto out; } } @@ -394,7 +405,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error) value = decode_unicode_escape(p); if(value < 0) { - error_set(error, lex, "invalid Unicode escape '%.6s'", p - 1); + error_set(error, lex, json_error_invalid_syntax, "invalid Unicode escape '%.6s'", p - 1); goto out; } p += 5; @@ -404,7 +415,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error) if(*p == '\\' && *(p + 1) == 'u') { int32_t value2 = decode_unicode_escape(++p); if(value2 < 0) { - error_set(error, lex, "invalid Unicode escape '%.6s'", p - 1); + error_set(error, lex, json_error_invalid_syntax, "invalid Unicode escape '%.6s'", p - 1); goto out; } p += 5; @@ -419,6 +430,7 @@ static void lex_scan_string(lex_t *lex, json_error_t *error) else { /* invalid second surrogate */ error_set(error, lex, + json_error_invalid_syntax, "invalid Unicode '\\u%04X\\u%04X'", value, value2); goto out; @@ -426,13 +438,13 @@ static void lex_scan_string(lex_t *lex, json_error_t *error) } else { /* no second surrogate */ - error_set(error, lex, "invalid Unicode '\\u%04X'", + error_set(error, lex, json_error_invalid_syntax, "invalid Unicode '\\u%04X'", value); goto out; } } else if(0xDC00 <= value && value <= 0xDFFF) { - error_set(error, lex, "invalid Unicode '\\u%04X'", value); + error_set(error, lex, json_error_invalid_syntax, "invalid Unicode '\\u%04X'", value); goto out; } @@ -483,7 +495,7 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error) { const char *saved_text; char *end; - double value; + double doubleval; lex->token = TOKEN_INVALID; @@ -498,36 +510,38 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error) } } else if(l_isdigit(c)) { - c = lex_get_save(lex, error); - while(l_isdigit(c)) + do c = lex_get_save(lex, error); + while(l_isdigit(c)); } else { lex_unget_unsave(lex, c); goto out; } - if(c != '.' && c != 'E' && c != 'e') { - json_int_t value; + if(!(lex->flags & JSON_DECODE_INT_AS_REAL) && + c != '.' && c != 'E' && c != 'e') + { + json_int_t intval; lex_unget_unsave(lex, c); saved_text = strbuffer_value(&lex->saved_text); errno = 0; - value = json_strtoint(saved_text, &end, 10); + intval = json_strtoint(saved_text, &end, 10); if(errno == ERANGE) { - if(value < 0) - error_set(error, lex, "too big negative integer"); + if(intval < 0) + error_set(error, lex, json_error_numeric_overflow, "too big negative integer"); else - error_set(error, lex, "too big integer"); + error_set(error, lex, json_error_numeric_overflow, "too big integer"); goto out; } assert(end == saved_text + lex->saved_text.length); lex->token = TOKEN_INTEGER; - lex->value.integer = value; + lex->value.integer = intval; return 0; } @@ -539,9 +553,9 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error) } lex_save(lex, c); - c = lex_get_save(lex, error); - while(l_isdigit(c)) + do c = lex_get_save(lex, error); + while(l_isdigit(c)); } if(c == 'E' || c == 'e') { @@ -554,20 +568,20 @@ static int lex_scan_number(lex_t *lex, int c, json_error_t *error) goto out; } - c = lex_get_save(lex, error); - while(l_isdigit(c)) + do c = lex_get_save(lex, error); + while(l_isdigit(c)); } lex_unget_unsave(lex, c); - if(jsonp_strtod(&lex->saved_text, &value)) { - error_set(error, lex, "real number overflow"); + if(jsonp_strtod(&lex->saved_text, &doubleval)) { + error_set(error, lex, json_error_numeric_overflow, "real number overflow"); goto out; } lex->token = TOKEN_REAL; - lex->value.real = value; + lex->value.real = doubleval; return 0; out: @@ -583,9 +597,9 @@ static int lex_scan(lex_t *lex, json_error_t *error) if(lex->token == TOKEN_STRING) lex_free_string(lex); - c = lex_get(lex, error); - while(c == ' ' || c == '\t' || c == '\n' || c == '\r') + do c = lex_get(lex, error); + while(c == ' ' || c == '\t' || c == '\n' || c == '\r'); if(c == STREAM_STATE_EOF) { lex->token = TOKEN_EOF; @@ -614,9 +628,9 @@ static int lex_scan(lex_t *lex, json_error_t *error) /* eat up the whole identifier for clearer error messages */ const char *saved_text; - c = lex_get_save(lex, error); - while(l_isalpha(c)) + do c = lex_get_save(lex, error); + while(l_isalpha(c)); lex_unget_unsave(lex, c); saved_text = strbuffer_value(&lex->saved_text); @@ -654,12 +668,13 @@ static char *lex_steal_string(lex_t *lex, size_t *out_len) return result; } -static int lex_init(lex_t *lex, get_func get, void *data) +static int lex_init(lex_t *lex, get_func get, size_t flags, void *data) { stream_init(&lex->stream, get, data); if(strbuffer_init(&lex->saved_text)) return -1; + lex->flags = flags; lex->token = TOKEN_INVALID; return 0; } @@ -692,7 +707,7 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) json_t *value; if(lex->token != TOKEN_STRING) { - error_set(error, lex, "string or '}' expected"); + error_set(error, lex, json_error_invalid_syntax, "string or '}' expected"); goto error; } @@ -701,14 +716,14 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) return NULL; if (memchr(key, '\0', len)) { jsonp_free(key); - error_set(error, lex, "NUL byte in object key not supported"); + error_set(error, lex, json_error_null_byte_in_key, "NUL byte in object key not supported"); goto error; } if(flags & JSON_REJECT_DUPLICATES) { if(json_object_get(object, key)) { jsonp_free(key); - error_set(error, lex, "duplicate object key"); + error_set(error, lex, json_error_duplicate_key, "duplicate object key"); goto error; } } @@ -716,7 +731,7 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) lex_scan(lex, error); if(lex->token != ':') { jsonp_free(key); - error_set(error, lex, "':' expected"); + error_set(error, lex, json_error_invalid_syntax, "':' expected"); goto error; } @@ -727,13 +742,11 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) goto error; } - if(json_object_set_nocheck(object, key, value)) { + if(json_object_set_new_nocheck(object, key, value)) { jsonp_free(key); - json_decref(value); goto error; } - json_decref(value); jsonp_free(key); lex_scan(lex, error); @@ -744,7 +757,7 @@ static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) } if(lex->token != '}') { - error_set(error, lex, "'}' expected"); + error_set(error, lex, json_error_invalid_syntax, "'}' expected"); goto error; } @@ -770,11 +783,9 @@ static json_t *parse_array(lex_t *lex, size_t flags, json_error_t *error) if(!elem) goto error; - if(json_array_append(array, elem)) { - json_decref(elem); + if(json_array_append_new(array, elem)) { goto error; } - json_decref(elem); lex_scan(lex, error); if(lex->token != ',') @@ -784,7 +795,7 @@ static json_t *parse_array(lex_t *lex, size_t flags, json_error_t *error) } if(lex->token != ']') { - error_set(error, lex, "']' expected"); + error_set(error, lex, json_error_invalid_syntax, "']' expected"); goto error; } @@ -798,7 +809,12 @@ error: static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error) { json_t *json; - double value; + + lex->depth++; + if(lex->depth > JSON_PARSER_MAX_DEPTH) { + error_set(error, lex, json_error_stack_overflow, "maximum parsing depth reached"); + return NULL; + } switch(lex->token) { case TOKEN_STRING: { @@ -807,29 +823,19 @@ static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error) if(!(flags & JSON_ALLOW_NUL)) { if(memchr(value, '\0', len)) { - error_set(error, lex, "\\u0000 is not allowed without JSON_ALLOW_NUL"); + error_set(error, lex, json_error_null_character, "\\u0000 is not allowed without JSON_ALLOW_NUL"); return NULL; } } json = jsonp_stringn_nocheck_own(value, len); - if(json) { - lex->value.string.val = NULL; - lex->value.string.len = 0; - } + lex->value.string.val = NULL; + lex->value.string.len = 0; break; } case TOKEN_INTEGER: { - if (flags & JSON_DECODE_INT_AS_REAL) { - if(jsonp_strtod(&lex->saved_text, &value)) { - error_set(error, lex, "real number overflow"); - return NULL; - } - json = json_real(value); - } else { - json = json_integer(lex->value.integer); - } + json = json_integer(lex->value.integer); break; } @@ -859,17 +865,18 @@ static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error) break; case TOKEN_INVALID: - error_set(error, lex, "invalid token"); + error_set(error, lex, json_error_invalid_syntax, "invalid token"); return NULL; default: - error_set(error, lex, "unexpected token"); + error_set(error, lex, json_error_invalid_syntax, "unexpected token"); return NULL; } if(!json) return NULL; + lex->depth--; return json; } @@ -877,10 +884,12 @@ static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error) { json_t *result; + lex->depth = 0; + lex_scan(lex, error); if(!(flags & JSON_DECODE_ANY)) { if(lex->token != '[' && lex->token != '{') { - error_set(error, lex, "'[' or '{' expected"); + error_set(error, lex, json_error_invalid_syntax, "'[' or '{' expected"); return NULL; } } @@ -892,7 +901,7 @@ static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error) if(!(flags & JSON_DISABLE_EOF_CHECK)) { lex_scan(lex, error); if(lex->token != TOKEN_EOF) { - error_set(error, lex, "end of file expected"); + error_set(error, lex, json_error_end_of_input_expected, "end of file expected"); json_decref(result); return NULL; } @@ -900,7 +909,7 @@ static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error) if(error) { /* Save the position even though there was no error */ - error->position = lex->stream.position; + error->position = (int)lex->stream.position; } return result; @@ -909,7 +918,7 @@ static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error) typedef struct { const char *data; - int pos; + size_t pos; } string_data_t; static int string_get(void *data) @@ -935,14 +944,14 @@ json_t *json_loads(const char *string, size_t flags, json_error_t *error) jsonp_error_init(error, "<string>"); if (string == NULL) { - error_set(error, NULL, "wrong arguments"); + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); return NULL; } stream_data.data = string; stream_data.pos = 0; - if(lex_init(&lex, string_get, (void *)&stream_data)) + if(lex_init(&lex, string_get, flags, (void *)&stream_data)) return NULL; result = parse_json(&lex, flags, error); @@ -979,7 +988,7 @@ json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t jsonp_error_init(error, "<buffer>"); if (buffer == NULL) { - error_set(error, NULL, "wrong arguments"); + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); return NULL; } @@ -987,7 +996,7 @@ json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t stream_data.pos = 0; stream_data.len = buflen; - if(lex_init(&lex, buffer_get, (void *)&stream_data)) + if(lex_init(&lex, buffer_get, flags, (void *)&stream_data)) return NULL; result = parse_json(&lex, flags, error); @@ -1010,11 +1019,50 @@ json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) jsonp_error_init(error, source); if (input == NULL) { - error_set(error, NULL, "wrong arguments"); + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); + return NULL; + } + + if(lex_init(&lex, (get_func)fgetc, flags, input)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +static int fd_get_func(int *fd) +{ +#ifdef HAVE_UNISTD_H + uint8_t c; + if (read(*fd, &c, 1) == 1) + return c; +#endif + return EOF; +} + +json_t *json_loadfd(int input, size_t flags, json_error_t *error) +{ + lex_t lex; + const char *source; + json_t *result; + +#ifdef HAVE_UNISTD_H + if(input == STDIN_FILENO) + source = "<stdin>"; + else +#endif + source = "<stream>"; + + jsonp_error_init(error, source); + + if (input < 0) { + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); return NULL; } - if(lex_init(&lex, (get_func)fgetc, input)) + if(lex_init(&lex, (get_func)fd_get_func, flags, &input)) return NULL; result = parse_json(&lex, flags, error); @@ -1031,14 +1079,14 @@ json_t *json_load_file(const char *path, size_t flags, json_error_t *error) jsonp_error_init(error, path); if (path == NULL) { - error_set(error, NULL, "wrong arguments"); + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); return NULL; } fp = fopen(path, "rb"); if(!fp) { - error_set(error, NULL, "unable to open %s: %s", + error_set(error, NULL, json_error_cannot_open_file, "unable to open %s: %s", path, strerror(errno)); return NULL; } @@ -1091,11 +1139,11 @@ json_t *json_load_callback(json_load_callback_t callback, void *arg, size_t flag jsonp_error_init(error, "<callback>"); if (callback == NULL) { - error_set(error, NULL, "wrong arguments"); + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); return NULL; } - if(lex_init(&lex, (get_func)callback_get, &stream_data)) + if(lex_init(&lex, (get_func)callback_get, flags, &stream_data)) return NULL; result = parse_json(&lex, flags, error); diff --git a/src/jansson/lookup3.h b/src/jansson/lookup3.h index 8847483..2fe4c25 100644 --- a/src/jansson/lookup3.h +++ b/src/jansson/lookup3.h @@ -205,7 +205,22 @@ static uint32_t hashlittle(const void *key, size_t length, uint32_t initval) if (HASH_LITTLE_ENDIAN && ((u.i & 0x3) == 0)) { const uint32_t *k = (const uint32_t *)key; /* read 32-bit chunks */ +/* Detect Valgrind or AddressSanitizer */ #ifdef VALGRIND +# define NO_MASKING_TRICK 1 +#else +# if defined(__has_feature) /* Clang */ +# if __has_feature(address_sanitizer) /* is ASAN enabled? */ +# define NO_MASKING_TRICK 1 +# endif +# else +# if defined(__SANITIZE_ADDRESS__) /* GCC 4.8.x, is ASAN enabled? */ +# define NO_MASKING_TRICK 1 +# endif +# endif +#endif + +#ifdef NO_MASKING_TRICK const uint8_t *k8; #endif @@ -230,7 +245,7 @@ static uint32_t hashlittle(const void *key, size_t length, uint32_t initval) * still catch it and complain. The masking trick does make the hash * noticably faster for short strings (like English words). */ -#ifndef VALGRIND +#ifndef NO_MASKING_TRICK switch(length) { @@ -344,17 +359,17 @@ static uint32_t hashlittle(const void *key, size_t length, uint32_t initval) /*-------------------------------- last block: affect all 32 bits of (c) */ switch(length) /* all the case statements fall through */ { - case 12: c+=((uint32_t)k[11])<<24; - case 11: c+=((uint32_t)k[10])<<16; - case 10: c+=((uint32_t)k[9])<<8; - case 9 : c+=k[8]; - case 8 : b+=((uint32_t)k[7])<<24; - case 7 : b+=((uint32_t)k[6])<<16; - case 6 : b+=((uint32_t)k[5])<<8; - case 5 : b+=k[4]; - case 4 : a+=((uint32_t)k[3])<<24; - case 3 : a+=((uint32_t)k[2])<<16; - case 2 : a+=((uint32_t)k[1])<<8; + case 12: c+=((uint32_t)k[11])<<24; /* fall through */ + case 11: c+=((uint32_t)k[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k[9])<<8; /* fall through */ + case 9 : c+=k[8]; /* fall through */ + case 8 : b+=((uint32_t)k[7])<<24; /* fall through */ + case 7 : b+=((uint32_t)k[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k[5])<<8; /* fall through */ + case 5 : b+=k[4]; /* fall through */ + case 4 : a+=((uint32_t)k[3])<<24; /* fall through */ + case 3 : a+=((uint32_t)k[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k[1])<<8; /* fall through */ case 1 : a+=k[0]; break; case 0 : return c; diff --git a/src/jansson/memory.c b/src/jansson/memory.c index ca44d6b..a2be5d2 100644 --- a/src/jansson/memory.c +++ b/src/jansson/memory.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org> + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> * Copyright (c) 2011-2012 Basile Starynkevitch <basile@starynkevitch.net> * * Jansson is free software; you can redistribute it and/or modify it @@ -59,3 +59,11 @@ void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn) do_malloc = malloc_fn; do_free = free_fn; } + +void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn) +{ + if (malloc_fn) + *malloc_fn = do_malloc; + if (free_fn) + *free_fn = do_free; +} diff --git a/src/jansson/pack_unpack.c b/src/jansson/pack_unpack.c index af381a5..3b99776 100644 --- a/src/jansson/pack_unpack.c +++ b/src/jansson/pack_unpack.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org> + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> * Copyright (c) 2011-2012 Graeme Smecher <graeme.smecher@mail.mcgill.ca> * * Jansson is free software; you can redistribute it and/or modify @@ -29,6 +29,7 @@ typedef struct { int line; int column; size_t pos; + int has_error; } scanner_t; #define token(scanner) ((scanner)->token.token) @@ -48,7 +49,6 @@ static const char * const type_names[] = { static const char unpack_value_starters[] = "{[siIbfFOon"; - static void scanner_init(scanner_t *s, json_error_t *error, size_t flags, const char *fmt) { @@ -61,6 +61,7 @@ static void scanner_init(scanner_t *s, json_error_t *error, s->line = 1; s->column = 0; s->pos = 0; + s->has_error = 0; } static void next_token(scanner_t *s) @@ -74,6 +75,9 @@ static void next_token(scanner_t *s) return; } + if (!token(s) && !*s->fmt) + return; + t = s->fmt; s->column++; s->pos++; @@ -96,7 +100,7 @@ static void next_token(scanner_t *s) s->token.column = s->column; s->token.pos = s->pos; - t++; + if (*t) t++; s->fmt = t; } @@ -106,13 +110,14 @@ static void prev_token(scanner_t *s) s->token = s->prev_token; } -static void set_error(scanner_t *s, const char *source, const char *fmt, ...) +static void set_error(scanner_t *s, const char *source, enum json_error_code code, + const char *fmt, ...) { va_list ap; va_start(ap, fmt); jsonp_error_vset(s->error, s->token.line, s->token.column, s->token.pos, - fmt, ap); + code, fmt, ap); jsonp_error_set_source(s->error, source); @@ -125,7 +130,7 @@ static json_t *pack(scanner_t *s, va_list *ap); /* ours will be set to 1 if jsonp_free() must be called for the result afterwards */ static char *read_string(scanner_t *s, va_list *ap, - const char *purpose, size_t *out_len, int *ours) + const char *purpose, size_t *out_len, int *ours, int optional) { char t; strbuffer_t strbuff; @@ -136,35 +141,46 @@ static char *read_string(scanner_t *s, va_list *ap, t = token(s); prev_token(s); + *ours = 0; if(t != '#' && t != '%' && t != '+') { /* Optimize the simple case */ str = va_arg(*ap, const char *); if(!str) { - set_error(s, "<args>", "NULL string argument"); + if (!optional) { + set_error(s, "<args>", json_error_null_value, "NULL %s", purpose); + s->has_error = 1; + } return NULL; } length = strlen(str); if(!utf8_check_string(str, length)) { - set_error(s, "<args>", "Invalid UTF-8 %s", purpose); + set_error(s, "<args>", json_error_invalid_utf8, "Invalid UTF-8 %s", purpose); + s->has_error = 1; return NULL; } *out_len = length; - *ours = 0; return (char *)str; + } else if (optional) { + set_error(s, "<format>", json_error_invalid_format, "Cannot use '%c' on optional strings", t); + s->has_error = 1; + + return NULL; } - strbuffer_init(&strbuff); + if(strbuffer_init(&strbuff)) { + set_error(s, "<internal>", json_error_out_of_memory, "Out of memory"); + s->has_error = 1; + } while(1) { str = va_arg(*ap, const char *); if(!str) { - set_error(s, "<args>", "NULL string argument"); - strbuffer_close(&strbuff); - return NULL; + set_error(s, "<args>", json_error_null_value, "NULL %s", purpose); + s->has_error = 1; } next_token(s); @@ -177,13 +193,12 @@ static char *read_string(scanner_t *s, va_list *ap, } else { prev_token(s); - length = strlen(str); + length = s->has_error ? 0 : strlen(str); } - if(strbuffer_append_bytes(&strbuff, str, length) == -1) { - set_error(s, "<internal>", "Out of memory"); - strbuffer_close(&strbuff); - return NULL; + if(!s->has_error && strbuffer_append_bytes(&strbuff, str, length) == -1) { + set_error(s, "<internal>", json_error_out_of_memory, "Out of memory"); + s->has_error = 1; } next_token(s); @@ -193,9 +208,15 @@ static char *read_string(scanner_t *s, va_list *ap, } } + if(s->has_error) { + strbuffer_close(&strbuff); + return NULL; + } + if(!utf8_check_string(strbuff.value, strbuff.length)) { - set_error(s, "<args>", "Invalid UTF-8 %s", purpose); + set_error(s, "<args>", json_error_invalid_utf8, "Invalid UTF-8 %s", purpose); strbuffer_close(&strbuff); + s->has_error = 1; return NULL; } @@ -214,37 +235,46 @@ static json_t *pack_object(scanner_t *s, va_list *ap) size_t len; int ours; json_t *value; + char valueOptional; if(!token(s)) { - set_error(s, "<format>", "Unexpected end of format string"); + set_error(s, "<format>", json_error_invalid_format, "Unexpected end of format string"); goto error; } if(token(s) != 's') { - set_error(s, "<format>", "Expected format 's', got '%c'", token(s)); + set_error(s, "<format>", json_error_invalid_format, "Expected format 's', got '%c'", token(s)); goto error; } - key = read_string(s, ap, "object key", &len, &ours); - if(!key) - goto error; + key = read_string(s, ap, "object key", &len, &ours, 0); + + next_token(s); next_token(s); + valueOptional = token(s); + prev_token(s); value = pack(s, ap); if(!value) { if(ours) jsonp_free(key); - goto error; + if(valueOptional != '*') { + set_error(s, "<args>", json_error_null_value, "NULL object value"); + s->has_error = 1; + } + + next_token(s); + continue; } - if(json_object_set_new_nocheck(object, key, value)) { - if(ours) - jsonp_free(key); + if(s->has_error) + json_decref(value); - set_error(s, "<internal>", "Unable to add key \"%s\"", key); - goto error; + if(!s->has_error && json_object_set_new_nocheck(object, key, value)) { + set_error(s, "<internal>", json_error_out_of_memory, "Unable to add key \"%s\"", key); + s->has_error = 1; } if(ours) @@ -253,7 +283,8 @@ static json_t *pack_object(scanner_t *s, va_list *ap) next_token(s); } - return object; + if(!s->has_error) + return object; error: json_decref(object); @@ -267,30 +298,143 @@ static json_t *pack_array(scanner_t *s, va_list *ap) while(token(s) != ']') { json_t *value; + char valueOptional; if(!token(s)) { - set_error(s, "<format>", "Unexpected end of format string"); + set_error(s, "<format>", json_error_invalid_format, "Unexpected end of format string"); + /* Format string errors are unrecoverable. */ goto error; } + next_token(s); + valueOptional = token(s); + prev_token(s); + value = pack(s, ap); - if(!value) - goto error; + if(!value) { + if(valueOptional != '*') { + s->has_error = 1; + } - if(json_array_append_new(array, value)) { - set_error(s, "<internal>", "Unable to append to array"); - goto error; + next_token(s); + continue; + } + + if(s->has_error) + json_decref(value); + + if(!s->has_error && json_array_append_new(array, value)) { + set_error(s, "<internal>", json_error_out_of_memory, "Unable to append to array"); + s->has_error = 1; } next_token(s); } - return array; + + if(!s->has_error) + return array; error: json_decref(array); return NULL; } +static json_t *pack_string(scanner_t *s, va_list *ap) +{ + char *str; + char t; + size_t len; + int ours; + int optional; + + next_token(s); + t = token(s); + optional = t == '?' || t == '*'; + if (!optional) + prev_token(s); + + str = read_string(s, ap, "string", &len, &ours, optional); + + if (!str) + return t == '?' && !s->has_error ? json_null() : NULL; + + if (s->has_error) { + /* It's impossible to reach this point if ours != 0, do not free str. */ + return NULL; + } + + if (ours) + return jsonp_stringn_nocheck_own(str, len); + + return json_stringn_nocheck(str, len); +} + +static json_t *pack_object_inter(scanner_t *s, va_list *ap, int need_incref) +{ + json_t *json; + char ntoken; + + next_token(s); + ntoken = token(s); + + if (ntoken != '?' && ntoken != '*') + prev_token(s); + + json = va_arg(*ap, json_t *); + + if (json) + return need_incref ? json_incref(json) : json; + + switch (ntoken) { + case '?': + return json_null(); + case '*': + return NULL; + default: + break; + } + + set_error(s, "<args>", json_error_null_value, "NULL object"); + s->has_error = 1; + return NULL; +} + +static json_t *pack_integer(scanner_t *s, json_int_t value) +{ + json_t *json = json_integer(value); + + if (!json) { + set_error(s, "<internal>", json_error_out_of_memory, "Out of memory"); + s->has_error = 1; + } + + return json; +} + +static json_t *pack_real(scanner_t *s, double value) +{ + /* Allocate without setting value so we can identify OOM error. */ + json_t *json = json_real(0.0); + + if (!json) { + set_error(s, "<internal>", json_error_out_of_memory, "Out of memory"); + s->has_error = 1; + + return NULL; + } + + if (json_real_set(json, value)) { + json_decref(json); + + set_error(s, "<args>", json_error_numeric_overflow, "Invalid floating point value"); + s->has_error = 1; + + return NULL; + } + + return json; +} + static json_t *pack(scanner_t *s, va_list *ap) { switch(token(s)) { @@ -301,20 +445,7 @@ static json_t *pack(scanner_t *s, va_list *ap) return pack_array(s, ap); case 's': /* string */ - { - char *str; - size_t len; - int ours; - - str = read_string(s, ap, "string", &len, &ours); - if(!str) - return NULL; - - if (ours) - return jsonp_stringn_nocheck_own(str, len); - else - return json_stringn_nocheck(str, len); - } + return pack_string(s, ap); case 'n': /* null */ return json_null(); @@ -323,23 +454,24 @@ static json_t *pack(scanner_t *s, va_list *ap) return va_arg(*ap, int) ? json_true() : json_false(); case 'i': /* integer from int */ - return json_integer(va_arg(*ap, int)); + return pack_integer(s, va_arg(*ap, int)); case 'I': /* integer from json_int_t */ - return json_integer(va_arg(*ap, json_int_t)); + return pack_integer(s, va_arg(*ap, json_int_t)); case 'f': /* real */ - return json_real(va_arg(*ap, double)); + return pack_real(s, va_arg(*ap, double)); case 'O': /* a json_t object; increments refcount */ - return json_incref(va_arg(*ap, json_t *)); + return pack_object_inter(s, ap, 1); case 'o': /* a json_t object; doesn't increment refcount */ - return va_arg(*ap, json_t *); + return pack_object_inter(s, ap, 0); default: - set_error(s, "<format>", "Unexpected format character '%c'", + set_error(s, "<format>", json_error_invalid_format, "Unexpected format character '%c'", token(s)); + s->has_error = 1; return NULL; } } @@ -360,12 +492,12 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) hashtable_t key_set; if(hashtable_init(&key_set)) { - set_error(s, "<internal>", "Out of memory"); + set_error(s, "<internal>", json_error_out_of_memory, "Out of memory"); return -1; } if(root && !json_is_object(root)) { - set_error(s, "<validation>", "Expected object, got %s", + set_error(s, "<validation>", json_error_wrong_type, "Expected object, got %s", type_name(root)); goto out; } @@ -377,13 +509,13 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) int opt = 0; if(strict != 0) { - set_error(s, "<format>", "Expected '}' after '%c', got '%c'", + set_error(s, "<format>", json_error_invalid_format, "Expected '}' after '%c', got '%c'", (strict == 1 ? '!' : '*'), token(s)); goto out; } if(!token(s)) { - set_error(s, "<format>", "Unexpected end of format string"); + set_error(s, "<format>", json_error_invalid_format, "Unexpected end of format string"); goto out; } @@ -394,13 +526,13 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) } if(token(s) != 's') { - set_error(s, "<format>", "Expected format 's', got '%c'", token(s)); + set_error(s, "<format>", json_error_invalid_format, "Expected format 's', got '%c'", token(s)); goto out; } key = va_arg(*ap, const char *); if(!key) { - set_error(s, "<args>", "NULL object key"); + set_error(s, "<args>", json_error_null_value, "NULL object key"); goto out; } @@ -418,7 +550,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) else { value = json_object_get(root, key); if(!value && !opt) { - set_error(s, "<validation>", "Object item not found: %s", key); + set_error(s, "<validation>", json_error_item_not_found, "Object item not found: %s", key); goto out; } } @@ -426,7 +558,7 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) if(unpack(s, value, ap)) goto out; - hashtable_set(&key_set, key, 0, json_null()); + hashtable_set(&key_set, key, json_null()); next_token(s); } @@ -436,21 +568,35 @@ static int unpack_object(scanner_t *s, json_t *root, va_list *ap) if(root && strict == 1) { /* We need to check that all non optional items have been parsed */ const char *key; + /* keys_res is 1 for uninitialized, 0 for success, -1 for error. */ + int keys_res = 1; + strbuffer_t unrecognized_keys; json_t *value; long unpacked = 0; - if (gotopt) { - /* We have optional keys, we need to iter on each key */ + + if (gotopt || json_object_size(root) != key_set.size) { json_object_foreach(root, key, value) { if(!hashtable_get(&key_set, key)) { unpacked++; + + /* Save unrecognized keys for the error message */ + if (keys_res == 1) { + keys_res = strbuffer_init(&unrecognized_keys); + } else if (!keys_res) { + keys_res = strbuffer_append_bytes(&unrecognized_keys, ", ", 2); + } + + if (!keys_res) + keys_res = strbuffer_append_bytes(&unrecognized_keys, key, strlen(key)); } } - } else { - /* No optional keys, we can just compare the number of items */ - unpacked = (long)json_object_size(root) - (long)key_set.size; } if (unpacked) { - set_error(s, "<validation>", "%li object item(s) left unpacked", unpacked); + set_error(s, "<validation>", json_error_end_of_input_expected, + "%li object item(s) left unpacked: %s", + unpacked, + keys_res ? "<unknown>" : strbuffer_value(&unrecognized_keys)); + strbuffer_close(&unrecognized_keys); goto out; } } @@ -468,7 +614,7 @@ static int unpack_array(scanner_t *s, json_t *root, va_list *ap) int strict = 0; if(root && !json_is_array(root)) { - set_error(s, "<validation>", "Expected array, got %s", type_name(root)); + set_error(s, "<validation>", json_error_wrong_type, "Expected array, got %s", type_name(root)); return -1; } next_token(s); @@ -477,14 +623,14 @@ static int unpack_array(scanner_t *s, json_t *root, va_list *ap) json_t *value; if(strict != 0) { - set_error(s, "<format>", "Expected ']' after '%c', got '%c'", + set_error(s, "<format>", json_error_invalid_format, "Expected ']' after '%c', got '%c'", (strict == 1 ? '!' : '*'), token(s)); return -1; } if(!token(s)) { - set_error(s, "<format>", "Unexpected end of format string"); + set_error(s, "<format>", json_error_invalid_format, "Unexpected end of format string"); return -1; } @@ -495,7 +641,7 @@ static int unpack_array(scanner_t *s, json_t *root, va_list *ap) } if(!strchr(unpack_value_starters, token(s))) { - set_error(s, "<format>", "Unexpected format character '%c'", + set_error(s, "<format>", json_error_invalid_format, "Unexpected format character '%c'", token(s)); return -1; } @@ -507,7 +653,7 @@ static int unpack_array(scanner_t *s, json_t *root, va_list *ap) else { value = json_array_get(root, i); if(!value) { - set_error(s, "<validation>", "Array index %lu out of range", + set_error(s, "<validation>", json_error_index_out_of_range, "Array index %lu out of range", (unsigned long)i); return -1; } @@ -525,7 +671,7 @@ static int unpack_array(scanner_t *s, json_t *root, va_list *ap) if(root && strict == 1 && i != json_array_size(root)) { long diff = (long)json_array_size(root) - (long)i; - set_error(s, "<validation>", "%li array item(s) left unpacked", diff); + set_error(s, "<validation>", json_error_end_of_input_expected, "%li array item(s) left unpacked", diff); return -1; } @@ -544,7 +690,7 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap) case 's': if(root && !json_is_string(root)) { - set_error(s, "<validation>", "Expected string, got %s", + set_error(s, "<validation>", json_error_wrong_type, "Expected string, got %s", type_name(root)); return -1; } @@ -555,7 +701,7 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap) str_target = va_arg(*ap, const char **); if(!str_target) { - set_error(s, "<args>", "NULL string argument"); + set_error(s, "<args>", json_error_null_value, "NULL string argument"); return -1; } @@ -564,7 +710,7 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap) if(token(s) == '%') { len_target = va_arg(*ap, size_t *); if(!len_target) { - set_error(s, "<args>", "NULL string length argument"); + set_error(s, "<args>", json_error_null_value, "NULL string length argument"); return -1; } } @@ -581,7 +727,7 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap) case 'i': if(root && !json_is_integer(root)) { - set_error(s, "<validation>", "Expected integer, got %s", + set_error(s, "<validation>", json_error_wrong_type, "Expected integer, got %s", type_name(root)); return -1; } @@ -596,7 +742,7 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap) case 'I': if(root && !json_is_integer(root)) { - set_error(s, "<validation>", "Expected integer, got %s", + set_error(s, "<validation>", json_error_wrong_type, "Expected integer, got %s", type_name(root)); return -1; } @@ -611,7 +757,7 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap) case 'b': if(root && !json_is_boolean(root)) { - set_error(s, "<validation>", "Expected true or false, got %s", + set_error(s, "<validation>", json_error_wrong_type, "Expected true or false, got %s", type_name(root)); return -1; } @@ -626,7 +772,7 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap) case 'f': if(root && !json_is_real(root)) { - set_error(s, "<validation>", "Expected real, got %s", + set_error(s, "<validation>", json_error_wrong_type, "Expected real, got %s", type_name(root)); return -1; } @@ -641,7 +787,7 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap) case 'F': if(root && !json_is_number(root)) { - set_error(s, "<validation>", "Expected real or integer, got %s", + set_error(s, "<validation>", json_error_wrong_type, "Expected real or integer, got %s", type_name(root)); return -1; } @@ -671,14 +817,14 @@ static int unpack(scanner_t *s, json_t *root, va_list *ap) case 'n': /* Never assign, just validate */ if(root && !json_is_null(root)) { - set_error(s, "<validation>", "Expected null, got %s", + set_error(s, "<validation>", json_error_wrong_type, "Expected null, got %s", type_name(root)); return -1; } return 0; default: - set_error(s, "<format>", "Unexpected format character '%c'", + set_error(s, "<format>", json_error_invalid_format, "Unexpected format character '%c'", token(s)); return -1; } @@ -693,7 +839,7 @@ json_t *json_vpack_ex(json_error_t *error, size_t flags, if(!fmt || !*fmt) { jsonp_error_init(error, "<format>"); - jsonp_error_set(error, -1, -1, 0, "NULL or empty format string"); + jsonp_error_set(error, -1, -1, 0, json_error_invalid_argument, "NULL or empty format string"); return NULL; } jsonp_error_init(error, NULL); @@ -705,13 +851,14 @@ json_t *json_vpack_ex(json_error_t *error, size_t flags, value = pack(&s, &ap_copy); va_end(ap_copy); + /* This will cover all situations where s.has_error is true */ if(!value) return NULL; next_token(&s); if(token(&s)) { json_decref(value); - set_error(&s, "<format>", "Garbage after format string"); + set_error(&s, "<format>", json_error_invalid_format, "Garbage after format string"); return NULL; } @@ -750,13 +897,13 @@ int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, if(!root) { jsonp_error_init(error, "<root>"); - jsonp_error_set(error, -1, -1, 0, "NULL root value"); + jsonp_error_set(error, -1, -1, 0, json_error_null_value, "NULL root value"); return -1; } if(!fmt || !*fmt) { jsonp_error_init(error, "<format>"); - jsonp_error_set(error, -1, -1, 0, "NULL or empty format string"); + jsonp_error_set(error, -1, -1, 0, json_error_invalid_argument, "NULL or empty format string"); return -1; } jsonp_error_init(error, NULL); @@ -773,7 +920,7 @@ int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, next_token(&s); if(token(&s)) { - set_error(&s, "<format>", "Garbage after format string"); + set_error(&s, "<format>", json_error_invalid_format, "Garbage after format string"); return -1; } diff --git a/src/jansson/strbuffer.c b/src/jansson/strbuffer.c index b3ddd0e..5e8c003 100644 --- a/src/jansson/strbuffer.c +++ b/src/jansson/strbuffer.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org> + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -60,11 +60,6 @@ char *strbuffer_steal_value(strbuffer_t *strbuff) return result; } -int strbuffer_append(strbuffer_t *strbuff, const char *string) -{ - return strbuffer_append_bytes(strbuff, string, strlen(string)); -} - int strbuffer_append_byte(strbuffer_t *strbuff, char byte) { return strbuffer_append_bytes(strbuff, &byte, 1); diff --git a/src/jansson/strbuffer.h b/src/jansson/strbuffer.h index fc11ec0..a0276d4 100644 --- a/src/jansson/strbuffer.h +++ b/src/jansson/strbuffer.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org> + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -8,13 +8,15 @@ #ifndef STRBUFFER_H #define STRBUFFER_H +#include <stdlib.h> + typedef struct { char *value; size_t length; /* bytes used */ size_t size; /* bytes allocated */ } strbuffer_t; -int strbuffer_init(strbuffer_t *strbuff); +int strbuffer_init(strbuffer_t *strbuff) JANSSON_ATTRS(warn_unused_result); void strbuffer_close(strbuffer_t *strbuff); void strbuffer_clear(strbuffer_t *strbuff); @@ -24,7 +26,6 @@ const char *strbuffer_value(const strbuffer_t *strbuff); /* Steal the value and close the strbuffer */ char *strbuffer_steal_value(strbuffer_t *strbuff); -int strbuffer_append(strbuffer_t *strbuff, const char *string); int strbuffer_append_byte(strbuffer_t *strbuff, char byte); int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size); diff --git a/src/jansson/strconv.c b/src/jansson/strconv.c index 3a70c6f..1cce56c 100644 --- a/src/jansson/strconv.c +++ b/src/jansson/strconv.c @@ -2,6 +2,10 @@ #include <errno.h> #include <stdio.h> #include <string.h> +#include <math.h> +#ifdef __MINGW32__ +#undef __NO_ISOCEXT /* ensure stdlib.h will declare prototypes for mingw own 'strtod' replacement, called '__strtod' */ +#endif #include "jansson_private.h" #include "strbuffer.h" @@ -10,6 +14,10 @@ #include <jansson_private_config.h> #endif +#ifdef __MINGW32__ +#define strtod __strtod +#endif + #if JSON_HAVE_LOCALECONV #include <locale.h> @@ -69,7 +77,7 @@ int jsonp_strtod(strbuffer_t *strbuffer, double *out) value = strtod(strbuffer->value, &end); assert(end == strbuffer->value + strbuffer->length); - if(errno == ERANGE && value != 0) { + if((value == __builtin_huge_val() || value == -__builtin_huge_val()) && errno == ERANGE) { /* Overflow */ return -1; } @@ -78,13 +86,16 @@ int jsonp_strtod(strbuffer_t *strbuffer, double *out) return 0; } -int jsonp_dtostr(char *buffer, size_t size, double value) +int jsonp_dtostr(char *buffer, size_t size, double value, int precision) { int ret; char *start, *end; size_t length; - ret = snprintf(buffer, size, "%.17g", value); + if (precision == 0) + precision = 17; + + ret = snprintf(buffer, size, "%.*g", precision, value); if(ret < 0) return -1; diff --git a/src/jansson/utf.c b/src/jansson/utf.c index b56e125..be966cb 100644 --- a/src/jansson/utf.c +++ b/src/jansson/utf.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org> + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. diff --git a/src/jansson/utf.h b/src/jansson/utf.h index 2cebea0..e182df7 100644 --- a/src/jansson/utf.h +++ b/src/jansson/utf.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org> + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. diff --git a/src/jansson/value.c b/src/jansson/value.c index 644bc87..3f964a0 100644 --- a/src/jansson/value.c +++ b/src/jansson/value.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2014 Petri Lehtinen <petri@digip.org> + * Copyright (c) 2009-2016 Petri Lehtinen <petri@digip.org> * * Jansson is free software; you can redistribute it and/or modify * it under the terms of the MIT license. See LICENSE for details. @@ -29,8 +29,10 @@ /* Work around nonstandard isnan() and isinf() implementations */ #ifndef isnan +#ifndef __sun static JSON_INLINE int isnan(double x) { return x != x; } #endif +#endif #ifndef isinf static JSON_INLINE int isinf(double x) { return !isnan(x) && isnan(x - x); } #endif @@ -65,9 +67,6 @@ json_t *json_object(void) return NULL; } - object->serial = 0; - object->visited = 0; - return &object->json; } @@ -113,7 +112,7 @@ int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) } object = json_to_object(json); - if(hashtable_set(&object->hashtable, key, object->serial++, value)) + if(hashtable_set(&object->hashtable, key, value)) { json_decref(value); return -1; @@ -152,9 +151,7 @@ int json_object_clear(json_t *json) return -1; object = json_to_object(json); - hashtable_clear(&object->hashtable); - object->serial = 0; return 0; } @@ -259,7 +256,10 @@ json_t *json_object_iter_value(void *iter) int json_object_iter_set_new(json_t *json, void *iter, json_t *value) { if(!json_is_object(json) || !iter || !value) + { + json_decref(value); return -1; + } hashtable_iter_set(iter, value); return 0; @@ -273,15 +273,15 @@ void *json_object_key_to_iter(const char *key) return hashtable_key_to_iter(key); } -static int json_object_equal(json_t *object1, json_t *object2) +static int json_object_equal(const json_t *object1, const json_t *object2) { const char *key; - json_t *value1, *value2; + const json_t *value1, *value2; if(json_object_size(object1) != json_object_size(object2)) return 0; - json_object_foreach(object1, key, value1) { + json_object_foreach((json_t *)object1, key, value1) { value2 = json_object_get(object2, key); if(!json_equal(value1, value2)) @@ -352,8 +352,6 @@ json_t *json_array(void) return NULL; } - array->visited = 0; - return &array->json; } @@ -582,7 +580,7 @@ int json_array_extend(json_t *json, json_t *other_json) return 0; } -static int json_array_equal(json_t *array1, json_t *array2) +static int json_array_equal(const json_t *array1, const json_t *array2) { size_t i, size; @@ -654,8 +652,7 @@ static json_t *string_create(const char *value, size_t len, int own) string = jsonp_malloc(sizeof(json_string_t)); if(!string) { - if(!own) - jsonp_free(v); + jsonp_free(v); return NULL; } json_init(&string->json, JSON_STRING); @@ -766,13 +763,10 @@ static void json_delete_string(json_string_t *string) jsonp_free(string); } -static int json_string_equal(json_t *string1, json_t *string2) +static int json_string_equal(const json_t *string1, const json_t *string2) { json_string_t *s1, *s2; - if(!json_is_string(string1) || !json_is_string(string2)) - return 0; - s1 = json_to_string(string1); s2 = json_to_string(string2); return s1->length == s2->length && !memcmp(s1->value, s2->value, s1->length); @@ -782,13 +776,51 @@ static json_t *json_string_copy(const json_t *string) { json_string_t *s; - if(!json_is_string(string)) - return NULL; - s = json_to_string(string); return json_stringn_nocheck(s->value, s->length); } +json_t *json_vsprintf(const char *fmt, va_list ap) { + json_t *json = NULL; + int length; + char *buf; + va_list aq; + va_copy(aq, ap); + + length = vsnprintf(NULL, 0, fmt, ap); + if (length == 0) { + json = json_string(""); + goto out; + } + + buf = jsonp_malloc(length + 1); + if (!buf) + goto out; + + vsnprintf(buf, length + 1, fmt, aq); + if (!utf8_check_string(buf, length)) { + jsonp_free(buf); + goto out; + } + + json = jsonp_stringn_nocheck_own(buf, length); + +out: + va_end(aq); + return json; +} + +json_t *json_sprintf(const char *fmt, ...) { + json_t *result; + va_list ap; + + va_start(ap, fmt); + result = json_vsprintf(fmt, ap); + va_end(ap); + + return result; +} + /*** integer ***/ @@ -826,7 +858,7 @@ static void json_delete_integer(json_integer_t *integer) jsonp_free(integer); } -static int json_integer_equal(json_t *integer1, json_t *integer2) +static int json_integer_equal(const json_t *integer1, const json_t *integer2) { return json_integer_value(integer1) == json_integer_value(integer2); } @@ -878,7 +910,7 @@ static void json_delete_real(json_real_t *real) jsonp_free(real); } -static int json_real_equal(json_t *real1, json_t *real2) +static int json_real_equal(const json_t *real1, const json_t *real2) { return json_real_value(real1) == json_real_value(real2); } @@ -929,20 +961,28 @@ json_t *json_null(void) void json_delete(json_t *json) { - if(json_is_object(json)) - json_delete_object(json_to_object(json)); - - else if(json_is_array(json)) - json_delete_array(json_to_array(json)); - - else if(json_is_string(json)) - json_delete_string(json_to_string(json)); - - else if(json_is_integer(json)) - json_delete_integer(json_to_integer(json)); - - else if(json_is_real(json)) - json_delete_real(json_to_real(json)); + if (!json) + return; + + switch(json_typeof(json)) { + case JSON_OBJECT: + json_delete_object(json_to_object(json)); + break; + case JSON_ARRAY: + json_delete_array(json_to_array(json)); + break; + case JSON_STRING: + json_delete_string(json_to_string(json)); + break; + case JSON_INTEGER: + json_delete_integer(json_to_integer(json)); + break; + case JSON_REAL: + json_delete_real(json_to_real(json)); + break; + default: + return; + } /* json_delete is not called for true, false or null */ } @@ -950,7 +990,7 @@ void json_delete(json_t *json) /*** equality ***/ -int json_equal(json_t *json1, json_t *json2) +int json_equal(const json_t *json1, const json_t *json2) { if(!json1 || !json2) return 0; @@ -962,22 +1002,20 @@ int json_equal(json_t *json1, json_t *json2) if(json1 == json2) return 1; - if(json_is_object(json1)) - return json_object_equal(json1, json2); - - if(json_is_array(json1)) - return json_array_equal(json1, json2); - - if(json_is_string(json1)) - return json_string_equal(json1, json2); - - if(json_is_integer(json1)) - return json_integer_equal(json1, json2); - - if(json_is_real(json1)) - return json_real_equal(json1, json2); - - return 0; + switch(json_typeof(json1)) { + case JSON_OBJECT: + return json_object_equal(json1, json2); + case JSON_ARRAY: + return json_array_equal(json1, json2); + case JSON_STRING: + return json_string_equal(json1, json2); + case JSON_INTEGER: + return json_integer_equal(json1, json2); + case JSON_REAL: + return json_real_equal(json1, json2); + default: + return 0; + } } @@ -988,25 +1026,24 @@ json_t *json_copy(json_t *json) if(!json) return NULL; - if(json_is_object(json)) - return json_object_copy(json); - - if(json_is_array(json)) - return json_array_copy(json); - - if(json_is_string(json)) - return json_string_copy(json); - - if(json_is_integer(json)) - return json_integer_copy(json); - - if(json_is_real(json)) - return json_real_copy(json); - - if(json_is_true(json) || json_is_false(json) || json_is_null(json)) - return json; - - return NULL; + switch(json_typeof(json)) { + case JSON_OBJECT: + return json_object_copy(json); + case JSON_ARRAY: + return json_array_copy(json); + case JSON_STRING: + return json_string_copy(json); + case JSON_INTEGER: + return json_integer_copy(json); + case JSON_REAL: + return json_real_copy(json); + case JSON_TRUE: + case JSON_FALSE: + case JSON_NULL: + return json; + default: + return NULL; + } } json_t *json_deep_copy(const json_t *json) @@ -1014,26 +1051,24 @@ json_t *json_deep_copy(const json_t *json) if(!json) return NULL; - if(json_is_object(json)) - return json_object_deep_copy(json); - - if(json_is_array(json)) - return json_array_deep_copy(json); - - /* for the rest of the types, deep copying doesn't differ from - shallow copying */ - - if(json_is_string(json)) - return json_string_copy(json); - - if(json_is_integer(json)) - return json_integer_copy(json); - - if(json_is_real(json)) - return json_real_copy(json); - - if(json_is_true(json) || json_is_false(json) || json_is_null(json)) - return (json_t *)json; - - return NULL; + switch(json_typeof(json)) { + case JSON_OBJECT: + return json_object_deep_copy(json); + case JSON_ARRAY: + return json_array_deep_copy(json); + /* for the rest of the types, deep copying doesn't differ from + shallow copying */ + case JSON_STRING: + return json_string_copy(json); + case JSON_INTEGER: + return json_integer_copy(json); + case JSON_REAL: + return json_real_copy(json); + case JSON_TRUE: + case JSON_FALSE: + case JSON_NULL: + return (json_t *)json; + default: + return NULL; + } } diff --git a/src/libXNVCtrl/version.mk b/src/libXNVCtrl/version.mk index 6942222..5e94d96 100644 --- a/src/libXNVCtrl/version.mk +++ b/src/libXNVCtrl/version.mk @@ -1 +1 @@ -NVIDIA_VERSION = 418.56 +NVIDIA_VERSION = 430.09 @@ -243,7 +243,7 @@ typedef enum nvmlNvLinkUtilizationCountUnits_enum NVML_NVLINK_COUNTER_UNIT_CYCLES = 0, // count by cycles NVML_NVLINK_COUNTER_UNIT_PACKETS = 1, // count by packets NVML_NVLINK_COUNTER_UNIT_BYTES = 2, // count by bytes - + NVML_NVLINK_COUNTER_UNIT_RESERVED = 3, // count reserved for internal use // this must be last NVML_NVLINK_COUNTER_UNIT_COUNT } nvmlNvLinkUtilizationCountUnits_t; @@ -5767,6 +5767,22 @@ nvmlReturn_t DECLDIR nvmlVgpuInstanceGetType(nvmlVgpuInstance_t vgpuInstance, nv nvmlReturn_t DECLDIR nvmlVgpuInstanceGetFrameRateLimit(nvmlVgpuInstance_t vgpuInstance, unsigned int *frameRateLimit); /** + * Retrieve the current ECC mode of vGPU instance. + * + * @param vgpuInstance The identifier of the target vGPU instance + * @param eccMode Reference in which to return the current ECC mode + * + * @return + * - \ref NVML_SUCCESS if the vgpuInstance's ECC mode has been successfully retrieved + * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a mode is NULL + * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system + * - \ref NVML_ERROR_NOT_SUPPORTED if the vGPU doesn't support this feature + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlVgpuInstanceGetEccMode(nvmlVgpuInstance_t vgpuInstance, nvmlEnableState_t *eccMode); + +/** * Retrieve the encoder capacity of a vGPU instance, as a percentage of maximum encoder capacity with valid values in the range 0-100. * * For Maxwell &tm; or newer fully supported devices. @@ -6056,11 +6072,11 @@ nvmlReturn_t DECLDIR nvmlDeviceGetProcessUtilization(nvmlDevice_t device, nvmlPr * * For Maxwell &tm; or newer fully supported devices. * - * @param vgpuInstance The identifier of the target vGPU VM + * @param vgpuInstance The identifier of the target vGPU instance * @param mode Reference in which to return the current accounting mode * - * @return - * - \ref NVML_SUCCESS if the mode has been successfully retrieved + * @return + * - \ref NVML_SUCCESS if the mode has been successfully retrieved * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a mode is NULL * - \ref NVML_ERROR_NOT_FOUND if \a vgpuInstance does not match a valid active vGPU instance on the system @@ -6070,24 +6086,24 @@ nvmlReturn_t DECLDIR nvmlDeviceGetProcessUtilization(nvmlDevice_t device, nvmlPr nvmlReturn_t DECLDIR nvmlVgpuInstanceGetAccountingMode(nvmlVgpuInstance_t vgpuInstance, nvmlEnableState_t *mode); /** - * Queries list of processes running on vGPU that can be queried for accounting stats. The list of processes + * Queries list of processes running on vGPU that can be queried for accounting stats. The list of processes * returned can be in running or terminated state. * * For Maxwell &tm; or newer fully supported devices. - * + * * To just query the maximum number of processes that can be queried, call this function with *count = 0 and * pids=NULL. The return code will be NVML_ERROR_INSUFFICIENT_SIZE, or NVML_SUCCESS if list is empty. - * + * * For more details see \ref nvmlVgpuInstanceGetAccountingStats. * * @note In case of PID collision some processes might not be accessible before the circular buffer is full. * - * @param vgpuInstance The identifier of the target vGPU VM + * @param vgpuInstance The identifier of the target vGPU instance * @param count Reference in which to provide the \a pids array size, and * to return the number of elements ready to be queried * @param pids Reference in which to return list of process ids - * - * @return + * + * @return * - \ref NVML_SUCCESS if pids were successfully retrieved * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a count is NULL @@ -6104,10 +6120,10 @@ nvmlReturn_t DECLDIR nvmlVgpuInstanceGetAccountingPids(nvmlVgpuInstance_t vgpuIn * Queries process's accounting stats. * * For Maxwell &tm; or newer fully supported devices. - * + * * Accounting stats capture GPU utilization and other statistics across the lifetime of a process, and * can be queried during life time of the process or after its termination. - * The time field in \ref nvmlAccountingStats_t is reported as 0 during the lifetime of the process and + * The time field in \ref nvmlAccountingStats_t is reported as 0 during the lifetime of the process and * updated to actual running time after its termination. * Accounting stats are kept in a circular buffer, newly created processes overwrite information about old * processes. @@ -6120,11 +6136,11 @@ nvmlReturn_t DECLDIR nvmlVgpuInstanceGetAccountingPids(nvmlVgpuInstance_t vgpuIn * queried since they don't contribute to GPU utilization. * @note In case of pid collision stats of only the latest process (that terminated last) will be reported * - * @param vgpuInstance The identifier of the target vGPU VM + * @param vgpuInstance The identifier of the target vGPU instance * @param pid Process Id of the target process to query stats for * @param stats Reference in which to return the process's accounting stats * - * @return + * @return * - \ref NVML_SUCCESS if stats have been successfully retrieved * - \ref NVML_ERROR_UNINITIALIZED if the library has not been successfully initialized * - \ref NVML_ERROR_INVALID_ARGUMENT if \a vgpuInstance is 0, or \a stats is NULL @@ -6292,6 +6308,26 @@ nvmlReturn_t DECLDIR nvmlDeviceGetVgpuMetadata(nvmlDevice_t device, nvmlVgpuPgpu */ nvmlReturn_t DECLDIR nvmlGetVgpuCompatibility(nvmlVgpuMetadata_t *vgpuMetadata, nvmlVgpuPgpuMetadata_t *pgpuMetadata, nvmlVgpuPgpuCompatibility_t *compatibilityInfo); +/** + * Returns the properties of the physical GPU indicated by the device in an ascii-encoded string format. + * + * The caller passes in a buffer via \a pgpuMetadata, with the size of the buffer in \a bufferSize. If the + * string is too large to fit in the supplied buffer, the function returns NVML_ERROR_INSUFFICIENT_SIZE with the size needed + * in \a bufferSize. + * + * @param device The identifier of the target device + * @param pgpuMetadata Pointer to caller-supplied buffer into which \a pgpuMetadata is written + * @param bufferSize Pointer to size of \a pgpuMetadata buffer + * + * @return + * - \ref NVML_SUCCESS GPU metadata structure was successfully returned + * - \ref NVML_ERROR_INSUFFICIENT_SIZE \a pgpuMetadata buffer is too small, required size is returned in \a bufferSize + * - \ref NVML_ERROR_INVALID_ARGUMENT if \a bufferSize is NULL or \a device is invalid; if \a pgpuMetadata is NULL and the value of \a bufferSize is not 0. + * - \ref NVML_ERROR_NOT_SUPPORTED if vGPU is not supported by the system + * - \ref NVML_ERROR_UNKNOWN on any unexpected error + */ +nvmlReturn_t DECLDIR nvmlDeviceGetPgpuMetadataString(nvmlDevice_t device, char *pgpuMetadata, unsigned int *bufferSize); + /* * Virtual GPU (vGPU) version * diff --git a/src/version.h b/src/version.h index dcde6d6..68e698d 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define NVIDIA_VERSION "418.56" +#define NVIDIA_VERSION "430.09" diff --git a/src/version.mk b/src/version.mk index 6942222..5e94d96 100644 --- a/src/version.mk +++ b/src/version.mk @@ -1 +1 @@ -NVIDIA_VERSION = 418.56 +NVIDIA_VERSION = 430.09 @@ -1 +1 @@ -NVIDIA_VERSION = 418.56 +NVIDIA_VERSION = 430.09 |