From: "Bruce A. Mah" <bmah@es.net>
Date: Fri, 3 Jun 2016 09:23:59 -0700
Subject: [PATCH] Fix a buffer overflow / heap corruption issue that could
 .
 https://github.com/esnet/iperf/commit/f01a9ca8f7e878e438a53687dabe30b7f7222912
 .
 occur if a malformed JSON string was passed on the control channel.  This
 issue, present in the cJSON library, was already fixed upstream, so was
 addressed here in iperf3 by importing a newer version of cJSON (plus local
 ESnet modifications).
 .
 Discovered and reported by Dave McDaniel, Cisco Talos.
 .
 Based on a patch by @dopheide-esnet, with input from @DaveGamble.
 .
 Cross-references:  TALOS-CAN-0164, ESNET-SECADV-2016-0001,
 CVE-2016-4303
 .
 (cherry picked from commit ed94082be27d971a5e1b08b666e2c217cf470a40)
 Signed-off-by: Bruce A. Mah <bmah@es.net>

Index: iperf3-3.0.7/configure.ac
===================================================================
--- iperf3-3.0.7.orig/configure.ac	2020-01-26 16:42:51.505980684 +0100
+++ iperf3-3.0.7/configure.ac	2020-01-26 17:57:34.875507671 +0100
@@ -7,7 +7,7 @@
 
 
 # Initialize the automake system
-AM_INIT_AUTOMAKE
+AM_INIT_AUTOMAKE([foreign])
 
 AM_MAINTAINER_MODE
 AM_CONFIG_HEADER(src/config.h)
@@ -37,6 +37,12 @@
 # Check for systems which need -lsocket and -lnsl
 #AX_LIB_SOCKET_NSL
 
+# Check for the math library (needed by cjson on some platforms)
+AC_SEARCH_LIBS(floor, [m], [], [
+echo "floor()"
+exit 1
+])
+
 # Solaris puts nanosleep in -lrt
 AC_SEARCH_LIBS(nanosleep, [rt], [], [
 echo "nanosleep() required for timing operations."
Index: iperf3-3.0.7/src/cjson.c
===================================================================
--- iperf3-3.0.7.orig/src/cjson.c	2020-01-26 16:42:51.505980684 +0100
+++ iperf3-3.0.7/src/cjson.c	2020-01-26 17:11:58.755202470 +0100
@@ -30,6 +30,9 @@
 #include <float.h>
 #include <limits.h>
 #include <ctype.h>
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
 #include <sys/types.h>
 #include "cjson.h"
 
@@ -39,994 +42,723 @@
 #ifndef LLONG_MIN
 #define LLONG_MIN (-LLONG_MAX - 1LL)
 #endif
+static const char *global_ep;
 
+const char *cJSON_GetErrorPtr(void) {return global_ep;}
 
-static const char *ep;
-
-const char *cJSON_GetErrorPtr( void )
-{
-	return ep;
-}
-
-
-static int cJSON_strcasecmp( const char *s1, const char *s2 )
+static int cJSON_strcasecmp(const char *s1,const char *s2)
 {
-	if ( ! s1 )
-		return ( s1 == s2 ) ? 0 : 1;
-	if ( ! s2 )
-		return 1;
-	for ( ; tolower(*s1) == tolower(*s2); ++s1, ++s2)
-		if( *s1 == 0 )
-			return 0;
+	if (!s1) return (s1==s2)?0:1;if (!s2) return 1;
+	for(; tolower(*s1) == tolower(*s2); ++s1, ++s2)	if(*s1 == 0)	return 0;
 	return tolower(*(const unsigned char *)s1) - tolower(*(const unsigned char *)s2);
 }
 
+static void *(*cJSON_malloc)(size_t sz) = malloc;
+static void (*cJSON_free)(void *ptr) = free;
 
-static void *(*cJSON_malloc)( size_t ) = malloc;
-static void (*cJSON_free)( void * ) = free;
-
-void cJSON_InitHooks(cJSON_Hooks* hooks)
+static char* cJSON_strdup(const char* str)
 {
-	if ( ! hooks ) {
-		/* Reset hooks. */
-		cJSON_malloc = malloc;
-		cJSON_free = free;
-		return;
-	}
-	cJSON_malloc = (hooks->malloc_fn) ? hooks->malloc_fn : malloc;
-	cJSON_free = (hooks->free_fn) ? hooks->free_fn : free;
-}
+      size_t len;
+      char* copy;
 
+      len = strlen(str) + 1;
+      if (!(copy = (char*)cJSON_malloc(len))) return 0;
+      memcpy(copy,str,len);
+      return copy;
+}
 
-static char* cJSON_strdup( const char* str )
+void cJSON_InitHooks(cJSON_Hooks* hooks)
 {
-	size_t len;
-	char* copy;
+    if (!hooks) { /* Reset hooks */
+        cJSON_malloc = malloc;
+        cJSON_free = free;
+        return;
+    }
 
-	len = strlen( str ) + 1;
-	if ( ! ( copy = (char*) cJSON_malloc( len ) ) )
-		return 0;
-	memcpy( copy, str, len );
-	return copy;
+	cJSON_malloc = (hooks->malloc_fn)?hooks->malloc_fn:malloc;
+	cJSON_free	 = (hooks->free_fn)?hooks->free_fn:free;
 }
 
-
 /* Internal constructor. */
-static cJSON *cJSON_New_Item( void )
+static cJSON *cJSON_New_Item(void)
 {
-	cJSON* node = (cJSON*) cJSON_malloc( sizeof(cJSON) );
-	if ( node )
-		memset( node, 0, sizeof(cJSON) );
+	cJSON* node = (cJSON*)cJSON_malloc(sizeof(cJSON));
+	if (node) memset(node,0,sizeof(cJSON));
 	return node;
 }
 
-
 /* Delete a cJSON structure. */
-void cJSON_Delete( cJSON *c )
+void cJSON_Delete(cJSON *c)
 {
 	cJSON *next;
-
-	while ( c ) {
-		next = c->next;
-		if ( ! ( c->type & cJSON_IsReference ) && c->child )
-			cJSON_Delete( c->child );
-		if ( ! ( c->type & cJSON_IsReference ) && c->valuestring )
-			cJSON_free( c->valuestring );
-		if ( c->string )
-			cJSON_free( c->string );
-		cJSON_free( c );
-		c = next;
+	while (c)
+	{
+		next=c->next;
+		if (!(c->type&cJSON_IsReference) && c->child) cJSON_Delete(c->child);
+		if (!(c->type&cJSON_IsReference) && c->valuestring) cJSON_free(c->valuestring);
+		if (!(c->type&cJSON_StringIsConst) && c->string) cJSON_free(c->string);
+		cJSON_free(c);
+		c=next;
 	}
 }
 
+/* Parse the input text to generate a number, and populate the result into item. */
+static const char *parse_number(cJSON *item,const char *num)
+{
+	double n=0,sign=1,scale=0;int subscale=0,signsubscale=1;
 
-static double ipow( double n, int exp )
-{
-	double r;
-
-	if ( exp < 0 )
-		return 1.0 / ipow( n, -exp );
-	r = 1;
-	while ( exp > 0 ) {
-		if ( exp & 1 )
-			r *= n;
-		exp >>= 1;
-		n *= n;
+	if (*num=='-') sign=-1,num++;	/* Has sign? */
+	if (*num=='0') num++;			/* is zero */
+	if (*num>='1' && *num<='9')	do	n=(n*10.0)+(*num++ -'0');	while (*num>='0' && *num<='9');	/* Number? */
+	if (*num=='.' && num[1]>='0' && num[1]<='9') {num++;		do	n=(n*10.0)+(*num++ -'0'),scale--; while (*num>='0' && *num<='9');}	/* Fractional part? */
+	if (*num=='e' || *num=='E')		/* Exponent? */
+	{	num++;if (*num=='+') num++;	else if (*num=='-') signsubscale=-1,num++;		/* With sign? */
+		while (*num>='0' && *num<='9') subscale=(subscale*10)+(*num++ - '0');	/* Number? */
 	}
-	return r;
+
+	n=sign*n*pow(10.0,(scale+subscale*signsubscale));	/* number = +/- number.fraction * 10^+/- exponent */
+
+	item->valuedouble=n;
+	item->valueint=(int64_t)n;
+	item->type=cJSON_Number;
+	return num;
 }
 
+static int pow2gt (int x)	{	--x;	x|=x>>1;	x|=x>>2;	x|=x>>4;	x|=x>>8;	x|=x>>16;	return x+1;	}
 
-/* Parse the input text to generate a number, and populate the result into item. */
-static const char *parse_number( cJSON *item, const char *num )
+typedef struct {char *buffer; int length; int offset; } printbuffer;
+
+static char* ensure(printbuffer *p,int needed)
 {
-	int64_t i = 0;
-	double f = 0;
-	int isint = 1;
-	int sign = 1, scale = 0, subscale = 0, signsubscale = 1;
-
-	/* Could use sscanf for this? */
-	if ( *num == '-' ) {
-		/* Has sign. */
-		sign = -1;
-		++num;
-	}
-	if ( *num == '0' )
-		/* Is zero. */
-		++num;
-	if ( *num >= '1' && *num<='9' ) {
-		/* Number. */
-		do {
-			i = ( i * 10 ) + ( *num - '0' );
-			f = ( f * 10.0 ) + ( *num - '0' );
-			++num;
-		} while ( *num >= '0' && *num <= '9' );
-	}
-	if ( *num == '.' && num[1] >= '0' && num[1] <= '9' ) {
-		/* Fractional part. */
-		isint = 0;
-		++num;
-		do {
-			f = ( f * 10.0 ) + ( *num++ - '0' );
-			scale--;
-		} while ( *num >= '0' && *num <= '9' );
-	}
-	if ( *num == 'e' || *num == 'E' ) {
-		/* Exponent. */
-		isint = 0;
-		++num;
-		if ( *num == '+' )
-			++num;
-		else if ( *num == '-' ) {
-			/* With sign. */
-			signsubscale = -1;
-			++num;
-		}
-		while ( *num >= '0' && *num <= '9' )
-			subscale = ( subscale * 10 ) + ( *num++ - '0' );
-	}
-
-	/* Put it together. */
-	if ( isint ) {
-		/* Int: number = +/- number */
-		i = sign * i;
-		item->valueint = i;
-		item->valuefloat = i;
-	} else {
-		/* Float: number = +/- number.fraction * 10^+/- exponent */
-		f = sign * f * ipow( 10.0, scale + subscale * signsubscale );
-		item->valueint = f;
-		item->valuefloat = f;
-	}
+	char *newbuffer;int newsize;
+	if (!p || !p->buffer) return 0;
+	needed+=p->offset;
+	if (needed<=p->length) return p->buffer+p->offset;
 
-	item->type = cJSON_Number;
-	return num;
+	newsize=pow2gt(needed);
+	newbuffer=(char*)cJSON_malloc(newsize);
+	if (!newbuffer) {cJSON_free(p->buffer);p->length=0,p->buffer=0;return 0;}
+	if (newbuffer) memcpy(newbuffer,p->buffer,p->length);
+	cJSON_free(p->buffer);
+	p->length=newsize;
+	p->buffer=newbuffer;
+	return newbuffer+p->offset;
 }
 
-
-/* Render the number nicely from the given item into a string. */
-static char *print_number( cJSON *item )
+static int update(printbuffer *p)
 {
 	char *str;
-	double f, f2;
-	int64_t i;
+	if (!p || !p->buffer) return 0;
+	str=p->buffer+p->offset;
+	return p->offset+strlen(str);
+}
 
-	str = (char*) cJSON_malloc( 64 );
-	if ( str ) {
-		f = item->valuefloat;
-		i = f;
-		f2 = i;
-		if ( f2 == f && item->valueint >= LLONG_MIN && item->valueint <= LLONG_MAX )
-			sprintf( str, "%lld", (long long) item->valueint );
-		else
-			sprintf( str, "%g", item->valuefloat );
+/* Render the number nicely from the given item into a string. */
+static char *print_number(cJSON *item,printbuffer *p)
+{
+	char *str=0;
+	double d=item->valuedouble;
+	if (d==0)
+	{
+		if (p)	str=ensure(p,2);
+		else	str=(char*)cJSON_malloc(2);	/* special case for 0. */
+		if (str) strcpy(str,"0");
+	}
+	else if (fabs(((double)item->valueint)-d)<=DBL_EPSILON && d<=LLONG_MAX && d>=LLONG_MIN)
+	{
+		if (p)	str=ensure(p,64);
+		else	str=(char*)cJSON_malloc(64);
+		if (str)	sprintf(str,"%lld",(long long) item->valueint);
+	}
+	else
+	{
+		if (p)	str=ensure(p,64);
+		else	str=(char*)cJSON_malloc(64);	/* This is a nice tradeoff. */
+		if (str)
+		{
+			if (fpclassify(d) != FP_ZERO && !isnormal(d))				sprintf(str,"null");
+			else if (fabs(floor(d)-d)<=DBL_EPSILON && fabs(d)<1.0e60)	sprintf(str,"%.0f",d);
+			else if (fabs(d)<1.0e-6 || fabs(d)>1.0e9)					sprintf(str,"%e",d);
+			else														sprintf(str,"%f",d);
+		}
 	}
 	return str;
 }
 
+static unsigned parse_hex4(const char *str)
+{
+	unsigned h=0;
+	if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+	h=h<<4;str++;
+	if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+	h=h<<4;str++;
+	if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+	h=h<<4;str++;
+	if (*str>='0' && *str<='9') h+=(*str)-'0'; else if (*str>='A' && *str<='F') h+=10+(*str)-'A'; else if (*str>='a' && *str<='f') h+=10+(*str)-'a'; else return 0;
+	return h;
+}
 
 /* Parse the input text into an unescaped cstring, and populate item. */
 static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
-
-static const char *parse_string( cJSON *item, const char *str )
+static const char *parse_string(cJSON *item,const char *str,const char **ep)
 {
-	const char *ptr = str + 1;
-	char *ptr2;
-	char *out;
-	int len = 0;
-	unsigned uc, uc2;
-
-	if ( *str != '\"' ) {
-		/* Not a string! */
-		ep = str;
-		return 0;
-	}
-	
-	/* Skip escaped quotes. */
-	while ( *ptr != '\"' && *ptr && ++len )
-		if ( *ptr++ == '\\' )
-			ptr++;
-	
-	if ( ! ( out = (char*) cJSON_malloc( len + 1 ) ) )
-		return 0;
-	
-	ptr = str + 1;
-	ptr2 = out;
-	while ( *ptr != '\"' && *ptr ) {
-		if ( *ptr != '\\' )
-			*ptr2++ = *ptr++;
-		else {
+	const char *ptr=str+1,*end_ptr=str+1;char *ptr2;char *out;int len=0;unsigned uc,uc2;
+	if (*str!='\"') {*ep=str;return 0;}	/* not a string! */
+
+	while (*end_ptr!='\"' && *end_ptr && ++len) if (*end_ptr++ == '\\') end_ptr++;	/* Skip escaped quotes. */
+
+	out=(char*)cJSON_malloc(len+1);	/* This is how long we need for the string, roughly. */
+	if (!out) return 0;
+	item->valuestring=out; /* assign here so out will be deleted during cJSON_Delete() later */
+	item->type=cJSON_String;
+
+	ptr=str+1;ptr2=out;
+	while (ptr < end_ptr)
+	{
+		if (*ptr!='\\') *ptr2++=*ptr++;
+		else
+		{
 			ptr++;
-			switch ( *ptr ) {
-				case 'b': *ptr2++ ='\b'; break;
-				case 'f': *ptr2++ ='\f'; break;
-				case 'n': *ptr2++ ='\n'; break;
-				case 'r': *ptr2++ ='\r'; break;
-				case 't': *ptr2++ ='\t'; break;
-				case 'u':
-					/* Transcode utf16 to utf8. */
-					/* Get the unicode char. */
-					sscanf( ptr + 1,"%4x", &uc );
-					ptr += 4;
-					/* Check for invalid. */
-					if ( ( uc >= 0xDC00 && uc <= 0xDFFF ) || uc == 0 )
-						break;
-
-					/* UTF16 surrogate pairs. */
-					if ( uc >= 0xD800 && uc <= 0xDBFF ) {
-						if ( ptr[1] != '\\' || ptr[2] != 'u' )
-							/* Missing second-half of surrogate. */
-							break;
-						sscanf( ptr + 3, "%4x", &uc2 );
-						ptr += 6;
-						if ( uc2 < 0xDC00 || uc2 > 0xDFFF )
-							/* Invalid second-half of surrogate. */
-							break;
-						uc = 0x10000 | ( ( uc & 0x3FF ) << 10 ) | ( uc2 & 0x3FF );
+			switch (*ptr)
+			{
+				case 'b': *ptr2++='\b';	break;
+				case 'f': *ptr2++='\f';	break;
+				case 'n': *ptr2++='\n';	break;
+				case 'r': *ptr2++='\r';	break;
+				case 't': *ptr2++='\t';	break;
+				case 'u':	 /* transcode utf16 to utf8. */
+					uc=parse_hex4(ptr+1);ptr+=4;	/* get the unicode char. */
+					if (ptr >= end_ptr) {*ep=str;return 0;}	/* invalid */
+
+					if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0)    {*ep=str;return 0;}	/* check for invalid.   */
+
+					if (uc>=0xD800 && uc<=0xDBFF)	/* UTF16 surrogate pairs.	*/
+					{
+						if (ptr+6 > end_ptr)    {*ep=str;return 0;}	/* invalid */
+						if (ptr[1]!='\\' || ptr[2]!='u')    {*ep=str;return 0;}	/* missing second-half of surrogate.    */
+						uc2=parse_hex4(ptr+3);ptr+=6;
+						if (uc2<0xDC00 || uc2>0xDFFF)       {*ep=str;return 0;}	/* invalid second-half of surrogate.    */
+						uc=0x10000 + (((uc&0x3FF)<<10) | (uc2&0x3FF));
 					}
 
-					len = 4;
-					if ( uc < 0x80 )
-						len = 1;
-					else if ( uc < 0x800 )
-						len = 2;
-					else if ( uc < 0x10000 )
-						len = 3;
-					ptr2 += len;
-					
-					switch ( len ) {
-						case 4: *--ptr2 = ( ( uc | 0x80) & 0xBF ); uc >>= 6;
-						case 3: *--ptr2 = ( ( uc | 0x80) & 0xBF ); uc >>= 6;
-						case 2: *--ptr2 = ( ( uc | 0x80) & 0xBF ); uc >>= 6;
-						case 1: *--ptr2 = ( uc | firstByteMark[len] );
+					len=4;if (uc<0x80) len=1;else if (uc<0x800) len=2;else if (uc<0x10000) len=3; ptr2+=len;
+
+					switch (len) {
+						case 4: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+						case 3: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+						case 2: *--ptr2 =((uc | 0x80) & 0xBF); uc >>= 6;
+						case 1: *--ptr2 =(uc | firstByteMark[len]);
 					}
-					ptr2 += len;
+					ptr2+=len;
 					break;
-				default:  *ptr2++ = *ptr; break;
+				default:  *ptr2++=*ptr; break;
 			}
-			++ptr;
+			ptr++;
 		}
 	}
-	*ptr2 = 0;
-	if ( *ptr == '\"' )
-		++ptr;
-	item->valuestring = out;
-	item->type = cJSON_String;
+	*ptr2=0;
+	if (*ptr=='\"') ptr++;
 	return ptr;
 }
 
-
 /* Render the cstring provided to an escaped version that can be printed. */
-static char *print_string_ptr( const char *str )
+static char *print_string_ptr(const char *str,printbuffer *p)
 {
-	const char *ptr;
-	char *ptr2, *out;
-	int len = 0;
-	unsigned char token;
-	
-	if ( ! str )
-		return cJSON_strdup( "" );
-	ptr = str;
-	while ( ( token = *ptr ) && ++len ) {
-		if ( strchr( "\"\\\b\f\n\r\t", token ) )
-			++len;
-		else if ( token < 32 )
-			len += 5;
-		++ptr;
-	}
-	
-	if ( ! ( out = (char*) cJSON_malloc( len + 3 ) ) )
-		return 0;
-
-	ptr2 = out;
-	ptr = str;
-	*ptr2++ = '\"';
-	while ( *ptr ) {
-		if ( (unsigned char) *ptr > 31 && *ptr != '\"' && *ptr != '\\' )
-			*ptr2++ = *ptr++;
-		else {
-			*ptr2++ = '\\';
-			switch ( token = *ptr++ ) {
-				case '\\': *ptr2++ = '\\'; break;
-				case '\"': *ptr2++ = '\"'; break;
-				case '\b': *ptr2++ = 'b'; break;
-				case '\f': *ptr2++ = 'f'; break;
-				case '\n': *ptr2++ = 'n'; break;
-				case '\r': *ptr2++ = 'r'; break;
-				case '\t': *ptr2++ = 't'; break;
-				default:
-				/* Escape and print. */
-				sprintf( ptr2, "u%04x", token );
-				ptr2 += 5;
-				break;
+	const char *ptr;char *ptr2,*out;int len=0,flag=0;unsigned char token;
+
+	if (!str)
+	{
+		if (p)	out=ensure(p,3);
+		else	out=(char*)cJSON_malloc(3);
+		if (!out) return 0;
+		strcpy(out,"\"\"");
+		return out;
+	}
+
+	for (ptr=str;*ptr;ptr++) flag|=((*ptr>0 && *ptr<32)||(*ptr=='\"')||(*ptr=='\\'))?1:0;
+	if (!flag)
+	{
+		len=ptr-str;
+		if (p) out=ensure(p,len+3);
+		else		out=(char*)cJSON_malloc(len+3);
+		if (!out) return 0;
+		ptr2=out;*ptr2++='\"';
+		strcpy(ptr2,str);
+		ptr2[len]='\"';
+		ptr2[len+1]=0;
+		return out;
+	}
+
+	ptr=str;while ((token=*ptr) && ++len) {if (strchr("\"\\\b\f\n\r\t",token)) len++; else if (token<32) len+=5;ptr++;}
+
+	if (p)	out=ensure(p,len+3);
+	else	out=(char*)cJSON_malloc(len+3);
+	if (!out) return 0;
+
+	ptr2=out;ptr=str;
+	*ptr2++='\"';
+	while (*ptr)
+	{
+		if ((unsigned char)*ptr>31 && *ptr!='\"' && *ptr!='\\') *ptr2++=*ptr++;
+		else
+		{
+			*ptr2++='\\';
+			switch (token=*ptr++)
+			{
+				case '\\':	*ptr2++='\\';	break;
+				case '\"':	*ptr2++='\"';	break;
+				case '\b':	*ptr2++='b';	break;
+				case '\f':	*ptr2++='f';	break;
+				case '\n':	*ptr2++='n';	break;
+				case '\r':	*ptr2++='r';	break;
+				case '\t':	*ptr2++='t';	break;
+				default: sprintf(ptr2,"u%04x",token);ptr2+=5;	break;	/* escape and print */
 			}
 		}
 	}
-	*ptr2++ = '\"';
-	*ptr2++ = 0;
+	*ptr2++='\"';*ptr2++=0;
 	return out;
 }
-
-
 /* Invote print_string_ptr (which is useful) on an item. */
-static char *print_string( cJSON *item )
-{
-	return print_string_ptr( item->valuestring );
-}
-
+static char *print_string(cJSON *item,printbuffer *p)	{return print_string_ptr(item->valuestring,p);}
 
 /* Predeclare these prototypes. */
-static const char *parse_value( cJSON *item, const char *value );
-static char *print_value( cJSON *item, int depth, int fmt );
-static const char *parse_array( cJSON *item, const char *value );
-static char *print_array( cJSON *item, int depth, int fmt );
-static const char *parse_object( cJSON *item, const char *value );
-static char *print_object( cJSON *item, int depth, int fmt );
-
-/* Utility to jump whitespace and cr/lf. */
-static const char *skip( const char *in )
-{
-	while ( in && *in && (unsigned char) *in <= 32 )
-		in++;
-	return in;
-}
+static const char *parse_value(cJSON *item,const char *value,const char **ep);
+static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p);
+static const char *parse_array(cJSON *item,const char *value,const char **ep);
+static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p);
+static const char *parse_object(cJSON *item,const char *value,const char **ep);
+static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p);
 
+/* Utility to jump whitespace and cr/lf */
+static const char *skip(const char *in) {while (in && *in && (unsigned char)*in<=32) in++; return in;}
 
 /* Parse an object - create a new root, and populate. */
-cJSON *cJSON_Parse( const char *value )
+cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated)
 {
-	cJSON *c;
-	ep = 0;
-	if ( ! ( c = cJSON_New_Item() ) )
-		return 0;	/* memory fail */
-
-	if ( ! parse_value( c, skip( value ) ) ) {
-		cJSON_Delete( c );
-		return 0;
-	}
+	const char *end=0,**ep=return_parse_end?return_parse_end:&global_ep;
+	cJSON *c=cJSON_New_Item();
+	*ep=0;
+	if (!c) return 0;       /* memory fail */
+
+	end=parse_value(c,skip(value),ep);
+	if (!end)	{cJSON_Delete(c);return 0;}	/* parse failure. ep is set. */
+
+	/* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */
+	if (require_null_terminated) {end=skip(end);if (*end) {cJSON_Delete(c);*ep=end;return 0;}}
+	if (return_parse_end) *return_parse_end=end;
 	return c;
 }
-
+/* Default options for cJSON_Parse */
+cJSON *cJSON_Parse(const char *value) {return cJSON_ParseWithOpts(value,0,0);}
 
 /* Render a cJSON item/entity/structure to text. */
-char *cJSON_Print( cJSON *item )
-{
-	return print_value( item, 0, 1 );
-}
-char *cJSON_PrintUnformatted( cJSON *item )
+char *cJSON_Print(cJSON *item)				{return print_value(item,0,1,0);}
+char *cJSON_PrintUnformatted(cJSON *item)	{return print_value(item,0,0,0);}
+
+char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt)
 {
-	return print_value( item, 0, 0 );
+	printbuffer p;
+	p.buffer=(char*)cJSON_malloc(prebuffer);
+	p.length=prebuffer;
+	p.offset=0;
+	return print_value(item,0,fmt,&p);
 }
 
 
 /* Parser core - when encountering text, process appropriately. */
-static const char *parse_value( cJSON *item, const char *value )
+static const char *parse_value(cJSON *item,const char *value,const char **ep)
 {
-	if ( ! value )
-		return 0;	/* Fail on null. */
-	if ( ! strncmp( value, "null", 4 ) ) {
-		item->type = cJSON_NULL;
-		return value + 4;
-	}
-	if ( ! strncmp( value, "false", 5 ) ) {
-		item->type = cJSON_False;
-		return value + 5;
-	}
-	if ( ! strncmp( value, "true", 4 ) ) {
-		item->type = cJSON_True;
-		item->valueint = 1;
-		return value + 4;
-	}
-	if ( *value == '\"' )
-		return parse_string( item, value );
-	if ( *value == '-' || ( *value >= '0' && *value <= '9' ) )
-		return parse_number( item, value );
-	if ( *value == '[' )
-		return parse_array( item, value );
-	if ( *value == '{' )
-		return parse_object( item, value );
-
-	/* Fail. */
-	ep = value;
-	return 0;
-}
+	if (!value)						return 0;	/* Fail on null. */
+	if (!strncmp(value,"null",4))	{ item->type=cJSON_NULL;  return value+4; }
+	if (!strncmp(value,"false",5))	{ item->type=cJSON_False; return value+5; }
+	if (!strncmp(value,"true",4))	{ item->type=cJSON_True; item->valueint=1;	return value+4; }
+	if (*value=='\"')				{ return parse_string(item,value,ep); }
+	if (*value=='-' || (*value>='0' && *value<='9'))	{ return parse_number(item,value); }
+	if (*value=='[')				{ return parse_array(item,value,ep); }
+	if (*value=='{')				{ return parse_object(item,value,ep); }
 
+	*ep=value;return 0;	/* failure. */
+}
 
 /* Render a value to text. */
-static char *print_value( cJSON *item, int depth, int fmt )
+static char *print_value(cJSON *item,int depth,int fmt,printbuffer *p)
 {
-	char *out = 0;
-
-	if ( ! item )
-		return 0;
-	switch ( ( item->type ) & 255 ) {
-		case cJSON_NULL:   out = cJSON_strdup( "null" ); break;
-		case cJSON_False:  out = cJSON_strdup( "false" ); break;
-		case cJSON_True:   out = cJSON_strdup( "true" ); break;
-		case cJSON_Number: out = print_number( item ); break;
-		case cJSON_String: out = print_string( item ); break;
-		case cJSON_Array:  out = print_array( item, depth, fmt ); break;
-		case cJSON_Object: out = print_object( item, depth, fmt ); break;
+	char *out=0;
+	if (!item) return 0;
+	if (p)
+	{
+		switch ((item->type)&255)
+		{
+			case cJSON_NULL:	{out=ensure(p,5);	if (out) strcpy(out,"null");	break;}
+			case cJSON_False:	{out=ensure(p,6);	if (out) strcpy(out,"false");	break;}
+			case cJSON_True:	{out=ensure(p,5);	if (out) strcpy(out,"true");	break;}
+			case cJSON_Number:	out=print_number(item,p);break;
+			case cJSON_String:	out=print_string(item,p);break;
+			case cJSON_Array:	out=print_array(item,depth,fmt,p);break;
+			case cJSON_Object:	out=print_object(item,depth,fmt,p);break;
+		}
+	}
+	else
+	{
+		switch ((item->type)&255)
+		{
+			case cJSON_NULL:	out=cJSON_strdup("null");	break;
+			case cJSON_False:	out=cJSON_strdup("false");break;
+			case cJSON_True:	out=cJSON_strdup("true"); break;
+			case cJSON_Number:	out=print_number(item,0);break;
+			case cJSON_String:	out=print_string(item,0);break;
+			case cJSON_Array:	out=print_array(item,depth,fmt,0);break;
+			case cJSON_Object:	out=print_object(item,depth,fmt,0);break;
+		}
 	}
 	return out;
 }
 
-
 /* Build an array from input text. */
-static const char *parse_array( cJSON *item, const char *value )
+static const char *parse_array(cJSON *item,const char *value,const char **ep)
 {
 	cJSON *child;
+	if (*value!='[')	{*ep=value;return 0;}	/* not an array! */
 
-	if ( *value != '[' ) {
-		/* Not an array! */
-		ep = value;
-		return 0;
-	}
-
-	item->type = cJSON_Array;
-	value = skip( value + 1 );
-	if ( *value == ']' )
-		return value + 1;	/* empty array. */
-
-	if ( ! ( item->child = child = cJSON_New_Item() ) )
-		return 0;		 /* memory fail */
-	if ( ! ( value = skip( parse_value( child, skip( value ) ) ) ) )
-		return 0;
+	item->type=cJSON_Array;
+	value=skip(value+1);
+	if (*value==']') return value+1;	/* empty array. */
+
+	item->child=child=cJSON_New_Item();
+	if (!item->child) return 0;		 /* memory fail */
+	value=skip(parse_value(child,skip(value),ep));	/* skip any spacing, get the value. */
+	if (!value) return 0;
 
-	while ( *value == ',' ) {
+	while (*value==',')
+	{
 		cJSON *new_item;
-		if ( ! ( new_item = cJSON_New_Item() ) )
-			return 0;	/* memory fail */
-		child->next = new_item;
-		new_item->prev = child;
-		child = new_item;
-		if ( ! ( value = skip( parse_value( child, skip( value+1 ) ) ) ) )
-			return 0;	/* memory fail */
+		if (!(new_item=cJSON_New_Item())) return 0; 	/* memory fail */
+		child->next=new_item;new_item->prev=child;child=new_item;
+		value=skip(parse_value(child,skip(value+1),ep));
+		if (!value) return 0;	/* memory fail */
 	}
 
-	if ( *value == ']' )
-		return value + 1;	/* end of array */
-	/* Malformed. */
-	ep = value;
-	return 0;
+	if (*value==']') return value+1;	/* end of array */
+	*ep=value;return 0;	/* malformed. */
 }
 
-
 /* Render an array to text */
-static char *print_array( cJSON *item, int depth, int fmt )
+static char *print_array(cJSON *item,int depth,int fmt,printbuffer *p)
 {
 	char **entries;
-	char *out = 0, *ptr, *ret;
-	int len = 5;
-	cJSON *child = item->child;
-	int numentries = 0, i = 0, fail = 0;
-	
+	char *out=0,*ptr,*ret;int len=5;
+	cJSON *child=item->child;
+	int numentries=0,i=0,fail=0;
+	size_t tmplen=0;
+
 	/* How many entries in the array? */
-	while ( child ) {
-		++numentries;
-		child = child->next;
-	}
-	/* Allocate an array to hold the values for each. */
-	if ( ! ( entries = (char**) cJSON_malloc( numentries * sizeof(char*) ) ) )
-		return 0;
-	memset( entries, 0, numentries * sizeof(char*) );
-	/* Retrieve all the results. */
-	child = item->child;
-	while ( child && ! fail ) {
-		ret = print_value( child, depth + 1, fmt );
-		entries[i++] = ret;
-		if ( ret )
-			len += strlen( ret ) + 2 + ( fmt ? 1 : 0 );
-		else
-			fail = 1;
-		child = child -> next;
+	while (child) numentries++,child=child->next;
+	/* Explicitly handle numentries==0 */
+	if (!numentries)
+	{
+		if (p)	out=ensure(p,3);
+		else	out=(char*)cJSON_malloc(3);
+		if (out) strcpy(out,"[]");
+		return out;
+	}
+
+	if (p)
+	{
+		/* Compose the output array. */
+		i=p->offset;
+		ptr=ensure(p,1);if (!ptr) return 0;	*ptr='[';	p->offset++;
+		child=item->child;
+		while (child && !fail)
+		{
+			print_value(child,depth+1,fmt,p);
+			p->offset=update(p);
+			if (child->next) {len=fmt?2:1;ptr=ensure(p,len+1);if (!ptr) return 0;*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;p->offset+=len;}
+			child=child->next;
+		}
+		ptr=ensure(p,2);if (!ptr) return 0;	*ptr++=']';*ptr=0;
+		out=(p->buffer)+i;
 	}
-	
-	/* If we didn't fail, try to malloc the output string. */
-	if ( ! fail ) {
-		out = (char*) cJSON_malloc( len );
-		if ( ! out )
-			fail = 1;
-	}
-
-	/* Handle failure. */
-	if ( fail ) {
-		for ( i = 0; i < numentries; ++i )
-			if ( entries[i] )
-				cJSON_free( entries[i] );
-		cJSON_free( entries );
-		return 0;
-	}
-	
-	/* Compose the output array. */
-	*out = '[';
-	ptr = out + 1;
-	*ptr = 0;
-	for ( i = 0; i < numentries; ++i ) {
-		strcpy( ptr, entries[i] );
-		ptr += strlen( entries[i] );
-		if ( i != numentries - 1 ) {
-			*ptr++ = ',';
-			if ( fmt )
-				*ptr++ = ' ';
-			*ptr = 0;
-		}
-		cJSON_free( entries[i] );
-	}
-	cJSON_free( entries );
-	*ptr++ = ']';
-	*ptr++ = 0;
-	return out;	
-}
-
-
-/* Build an object from the text. */
-static const char *parse_object( cJSON *item, const char *value )
-{
-	cJSON *child;
+	else
+	{
+		/* Allocate an array to hold the values for each */
+		entries=(char**)cJSON_malloc(numentries*sizeof(char*));
+		if (!entries) return 0;
+		memset(entries,0,numentries*sizeof(char*));
+		/* Retrieve all the results: */
+		child=item->child;
+		while (child && !fail)
+		{
+			ret=print_value(child,depth+1,fmt,0);
+			entries[i++]=ret;
+			if (ret) len+=strlen(ret)+2+(fmt?1:0); else fail=1;
+			child=child->next;
+		}
 
-	if ( *value != '{' ) {
-		/* Not an object! */
-		ep = value;
-		return 0;
-	}
-	
-	item->type = cJSON_Object;
-	value =skip( value + 1 );
-	if ( *value == '}' )
-		return value + 1;	/* empty array. */
-	
-	if ( ! ( item->child = child = cJSON_New_Item() ) )
-		return 0;
-	if ( ! ( value = skip( parse_string( child, skip( value ) ) ) ) )
-		return 0;
-	child->string = child->valuestring;
-	child->valuestring = 0;
-	if ( *value != ':' ) {
-		/* Fail! */
-		ep = value;
-		return 0;
-	}
-	if ( ! ( value = skip( parse_value( child, skip( value + 1 ) ) ) ) )
-		return 0;
-	
-	while ( *value == ',' ) {
-		cJSON *new_item;
-		if ( ! ( new_item = cJSON_New_Item() ) )
-			return 0;	/* memory fail */
-		child->next = new_item;
-		new_item->prev = child;
-		child = new_item;
-		if ( ! ( value = skip( parse_string( child, skip( value + 1 ) ) ) ) )
-			return 0;
-		child->string = child->valuestring;
-		child->valuestring = 0;
-		if ( *value != ':' ) {
-			/* Fail! */
-			ep = value;
+		/* If we didn't fail, try to malloc the output string */
+		if (!fail)	out=(char*)cJSON_malloc(len);
+		/* If that fails, we fail. */
+		if (!out) fail=1;
+
+		/* Handle failure. */
+		if (fail)
+		{
+			for (i=0;i<numentries;i++) if (entries[i]) cJSON_free(entries[i]);
+			cJSON_free(entries);
 			return 0;
 		}
-		if ( ! ( value = skip( parse_value( child, skip( value + 1 ) ) ) ) )
-			return 0;
-	}
-	
-	if ( *value == '}' )
-		return value + 1;	/* end of array */
-	/* Malformed. */
-	ep = value;
-	return 0;
-}
 
-
-/* Render an object to text. */
-static char *print_object( cJSON *item, int depth, int fmt )
-{
-	char **entries = 0, **names = 0;
-	char *out = 0, *ptr, *ret, *str;
-	int len = 7, i = 0, j;
-	cJSON *child = item->child;
-	int numentries = 0, fail = 0;
-
-	/* Count the number of entries. */
-	while ( child ) {
-		++numentries;
-		child = child->next;
-	}
-	/* Allocate space for the names and the objects. */
-	if ( ! ( entries = (char**) cJSON_malloc( numentries * sizeof(char*) ) ) )
-		return 0;
-	if ( ! ( names = (char**) cJSON_malloc( numentries * sizeof(char*) ) ) ) {
-		cJSON_free( entries );
-		return 0;
-	}
-	memset( entries, 0, sizeof(char*) * numentries );
-	memset( names, 0, sizeof(char*) * numentries );
-
-	/* Collect all the results into our arrays. */
-	child = item->child;
-	++depth;
-	if ( fmt )
-		len += depth;
-	while ( child ) {
-		names[i] = str = print_string_ptr( child->string );
-		entries[i++] = ret = print_value( child, depth, fmt );
-		if ( str && ret )
-			len += strlen( ret ) + strlen( str ) + 2 + ( fmt ? 2 + depth : 0 );
-		else
-			fail = 1;
-		child = child->next;
-	}
-	
-	/* Try to allocate the output string. */
-	if ( ! fail ) {
-		out = (char*) cJSON_malloc( len );
-		if ( ! out )
-			fail = 1;
-	}
-
-	/* Handle failure. */
-	if ( fail ) {
-		for ( i = 0; i < numentries; ++i ) {
-			if ( names[i] )
-				cJSON_free( names[i] );
-			if ( entries[i] )
-				cJSON_free( entries[i] );
-		}
-		cJSON_free( names );
-		cJSON_free( entries );
-		return 0;
-	}
-	
-	/* Compose the output. */
-	*out = '{';
-	ptr = out + 1;
-	if ( fmt )
-		*ptr++ = '\n';
-	*ptr = 0;
-	for ( i = 0; i < numentries; ++i ) {
-		if ( fmt )
-			for ( j = 0; j < depth; ++j )
-				*ptr++ = '\t';
-		strcpy( ptr, names[i] );
-		ptr += strlen( names[i] );
-		*ptr++ = ':';
-		if ( fmt )
-			*ptr++ = '\t';
-		strcpy( ptr, entries[i] );
-		ptr += strlen( entries[i] );
-		if ( i != numentries - 1 )
-			*ptr++ = ',';
-		if ( fmt )
-			*ptr++ = '\n';
-		*ptr = 0;
-		cJSON_free( names[i] );
-		cJSON_free( entries[i] );
-	}
-	
-	cJSON_free( names );
-	cJSON_free( entries );
-	if ( fmt )
-		for ( i = 0; i < depth - 1; ++i )
-			*ptr++ = '\t';
-	*ptr++ = '}';
-	*ptr++ = 0;
-	return out;	
-}
-
-
-int cJSON_GetArraySize( cJSON *array )
-{
-	cJSON *c = array->child;
-	int i = 0;
-	while ( c ) {
-		++i;
-		c = c->next;
-	}
-	return i;
-}
-
-
-cJSON *cJSON_GetArrayItem( cJSON *array, int item )
-{
-	cJSON *c = array->child;
-	while ( c && item > 0 ) {
-		--item;
-		c = c->next;
+		/* Compose the output array. */
+		*out='[';
+		ptr=out+1;*ptr=0;
+		for (i=0;i<numentries;i++)
+		{
+			tmplen=strlen(entries[i]);memcpy(ptr,entries[i],tmplen);ptr+=tmplen;
+			if (i!=numentries-1) {*ptr++=',';if(fmt)*ptr++=' ';*ptr=0;}
+			cJSON_free(entries[i]);
+		}
+		cJSON_free(entries);
+		*ptr++=']';*ptr++=0;
 	}
-	return c;
-}
-
-
-cJSON *cJSON_GetObjectItem( cJSON *object, const char *string )
-{
-	cJSON *c = object->child;
-	while ( c && cJSON_strcasecmp( c->string, string ) )
-		c = c->next;
-	return c;
-}
-
-
-/* Utility for array list handling. */
-static void suffix_object( cJSON *prev, cJSON *item )
-{
-	prev->next = item;
-	item->prev = prev;
+	return out;
 }
 
-
-/* Utility for handling references. */
-static cJSON *create_reference( cJSON *item )
+/* Build an object from the text. */
+static const char *parse_object(cJSON *item,const char *value,const char **ep)
 {
-	cJSON *ref;
-	if ( ! ( ref = cJSON_New_Item() ) )
-		return 0;
-	memcpy( ref, item, sizeof(cJSON) );
-	ref->string = 0;
-	ref->type |= cJSON_IsReference;
-	ref->next = ref->prev = 0;
-	return ref;
-}
+	cJSON *child;
+	if (*value!='{')	{*ep=value;return 0;}	/* not an object! */
 
+	item->type=cJSON_Object;
+	value=skip(value+1);
+	if (*value=='}') return value+1;	/* empty array. */
+
+	item->child=child=cJSON_New_Item();
+	if (!item->child) return 0;
+	value=skip(parse_string(child,skip(value),ep));
+	if (!value) return 0;
+	child->string=child->valuestring;child->valuestring=0;
+	if (*value!=':') {*ep=value;return 0;}	/* fail! */
+	value=skip(parse_value(child,skip(value+1),ep));	/* skip any spacing, get the value. */
+	if (!value) return 0;
 
-/* Add item to array/object. */
-void cJSON_AddItemToArray( cJSON *array, cJSON *item )
-{
-	cJSON *c = array->child;
-	if ( ! item )
-		return;
-	if ( ! c ) {
-		array->child = item;
-	} else {
-		while ( c && c->next )
-			c = c->next;
-		suffix_object( c, item );
+	while (*value==',')
+	{
+		cJSON *new_item;
+		if (!(new_item=cJSON_New_Item()))	return 0; /* memory fail */
+		child->next=new_item;new_item->prev=child;child=new_item;
+		value=skip(parse_string(child,skip(value+1),ep));
+		if (!value) return 0;
+		child->string=child->valuestring;child->valuestring=0;
+		if (*value!=':') {*ep=value;return 0;}	/* fail! */
+		value=skip(parse_value(child,skip(value+1),ep));	/* skip any spacing, get the value. */
+		if (!value) return 0;
 	}
-}
 
-void cJSON_AddItemToObject( cJSON *object, const char *string, cJSON *item )
-{
-	if ( ! item )
-		return;
-	if ( item->string )
-		cJSON_free( item->string );
-	item->string = cJSON_strdup( string );
-	cJSON_AddItemToArray( object, item );
-}
-
-void cJSON_AddItemReferenceToArray( cJSON *array, cJSON *item )
-{
-	cJSON_AddItemToArray( array, create_reference( item ) );
+	if (*value=='}') return value+1;	/* end of array */
+	*ep=value;return 0;	/* malformed. */
 }
 
-void cJSON_AddItemReferenceToObject( cJSON *object, const char *string, cJSON *item )
-{
-	cJSON_AddItemToObject( object, string, create_reference( item ) );
-}
-
-cJSON *cJSON_DetachItemFromArray( cJSON *array, int which )
-{
-	cJSON *c = array->child;
-	while ( c && which > 0 ) {
-		c = c->next;
-		--which;
-	}
-	if ( ! c )
-		return 0;
-	if ( c->prev )
-		c->prev->next = c->next;
-	if ( c->next ) c->next->prev = c->prev;
-	if ( c == array->child )
-		array->child = c->next;
-	c->prev = c->next = 0;
-	return c;
-}
-
-void cJSON_DeleteItemFromArray( cJSON *array, int which )
+/* Render an object to text. */
+static char *print_object(cJSON *item,int depth,int fmt,printbuffer *p)
 {
-	cJSON_Delete( cJSON_DetachItemFromArray( array, which ) );
-}
+	char **entries=0,**names=0;
+	char *out=0,*ptr,*ret,*str;int len=7,i=0,j;
+	cJSON *child=item->child;
+	int numentries=0,fail=0;
+	size_t tmplen=0;
+	/* Count the number of entries. */
+	while (child) numentries++,child=child->next;
+	/* Explicitly handle empty object case */
+	if (!numentries)
+	{
+		if (p) out=ensure(p,fmt?depth+4:3);
+		else	out=(char*)cJSON_malloc(fmt?depth+4:3);
+		if (!out)	return 0;
+		ptr=out;*ptr++='{';
+		if (fmt) {*ptr++='\n';for (i=0;i<depth;i++) *ptr++='\t';}
+		*ptr++='}';*ptr++=0;
+		return out;
+	}
+	if (p)
+	{
+		/* Compose the output: */
+		i=p->offset;
+		len=fmt?2:1;	ptr=ensure(p,len+1);	if (!ptr) return 0;
+		*ptr++='{';	if (fmt) *ptr++='\n';	*ptr=0;	p->offset+=len;
+		child=item->child;depth++;
+		while (child)
+		{
+			if (fmt)
+			{
+				ptr=ensure(p,depth);	if (!ptr) return 0;
+				for (j=0;j<depth;j++) *ptr++='\t';
+				p->offset+=depth;
+			}
+			print_string_ptr(child->string,p);
+			p->offset=update(p);
 
-cJSON *cJSON_DetachItemFromObject( cJSON *object, const char *string )
-{
-	int i = 0;
-	cJSON *c = object->child;
-	while ( c && cJSON_strcasecmp( c->string, string ) ) {
-		++i;
-		c = c->next;
+			len=fmt?2:1;
+			ptr=ensure(p,len);	if (!ptr) return 0;
+			*ptr++=':';if (fmt) *ptr++='\t';
+			p->offset+=len;
+
+			print_value(child,depth,fmt,p);
+			p->offset=update(p);
+
+			len=(fmt?1:0)+(child->next?1:0);
+			ptr=ensure(p,len+1); if (!ptr) return 0;
+			if (child->next) *ptr++=',';
+			if (fmt) *ptr++='\n';*ptr=0;
+			p->offset+=len;
+			child=child->next;
+		}
+		ptr=ensure(p,fmt?(depth+1):2);	 if (!ptr) return 0;
+		if (fmt)	for (i=0;i<depth-1;i++) *ptr++='\t';
+		*ptr++='}';*ptr=0;
+		out=(p->buffer)+i;
 	}
-	if ( c )
-		return cJSON_DetachItemFromArray( object, i );
-	return 0;
-}
-
-void cJSON_DeleteItemFromObject( cJSON *object, const char *string )
-{
-	cJSON_Delete( cJSON_DetachItemFromObject( object, string ) );
-}
-
-/* Replace array/object items with new ones. */
-void cJSON_ReplaceItemInArray( cJSON *array, int which, cJSON *newitem )
-{
-	cJSON *c = array->child;
-	while ( c && which > 0 ) {
-		c = c->next;
-		--which;
-	}
-	if ( ! c )
-		return;
-	newitem->next = c->next;
-	newitem->prev = c->prev;
-	if ( newitem->next )
-		newitem->next->prev = newitem;
-	if ( c == array->child )
-		array->child = newitem;
 	else
-		newitem->prev->next = newitem;
-	c->next = c->prev = 0;
-	cJSON_Delete( c );
-}
-
-void cJSON_ReplaceItemInObject( cJSON *object, const char *string, cJSON *newitem )
-{
-	int i = 0;
-	cJSON *c = object->child;
-	while ( c && cJSON_strcasecmp( c->string, string ) ) {
-		++i;
-		c = c->next;
-	}
-	if ( c ) {
-		newitem->string = cJSON_strdup( string );
-		cJSON_ReplaceItemInArray( object, i, newitem );
-	}
-}
-
-
-/* Create basic types: */
-
-cJSON *cJSON_CreateNull( void )
-{
-	cJSON *item = cJSON_New_Item();
-	if ( item )
-		item->type = cJSON_NULL;
-	return item;
-}
-
-cJSON *cJSON_CreateTrue( void )
-{
-	cJSON *item = cJSON_New_Item();
-	if ( item )
-		item->type = cJSON_True;
-	return item;
-}
-
-cJSON *cJSON_CreateFalse( void )
-{
-	cJSON *item = cJSON_New_Item();
-	if ( item )
-		item->type = cJSON_False;
-	return item;
-}
-
-cJSON *cJSON_CreateBool( int b )
-{
-	cJSON *item = cJSON_New_Item();
-	if ( item )
-		item->type = b ? cJSON_True : cJSON_False;
-	return item;
-}
+	{
+		/* Allocate space for the names and the objects */
+		entries=(char**)cJSON_malloc(numentries*sizeof(char*));
+		if (!entries) return 0;
+		names=(char**)cJSON_malloc(numentries*sizeof(char*));
+		if (!names) {cJSON_free(entries);return 0;}
+		memset(entries,0,sizeof(char*)*numentries);
+		memset(names,0,sizeof(char*)*numentries);
+
+		/* Collect all the results into our arrays: */
+		child=item->child;depth++;if (fmt) len+=depth;
+		while (child && !fail)
+		{
+			names[i]=str=print_string_ptr(child->string,0);
+			entries[i++]=ret=print_value(child,depth,fmt,0);
+			if (str && ret) len+=strlen(ret)+strlen(str)+2+(fmt?2+depth:0); else fail=1;
+			child=child->next;
+		}
 
-cJSON *cJSON_CreateInt( int64_t num )
-{
-	cJSON *item = cJSON_New_Item();
-	if ( item ) {
-		item->type = cJSON_Number;
-		item->valuefloat = num;
-		item->valueint = num;
-	}
-	return item;
-}
+		/* Try to allocate the output string */
+		if (!fail)	out=(char*)cJSON_malloc(len);
+		if (!out) fail=1;
+
+		/* Handle failure */
+		if (fail)
+		{
+			for (i=0;i<numentries;i++) {if (names[i]) cJSON_free(names[i]);if (entries[i]) cJSON_free(entries[i]);}
+			cJSON_free(names);cJSON_free(entries);
+			return 0;
+		}
 
-cJSON *cJSON_CreateFloat( double num )
-{
-	cJSON *item = cJSON_New_Item();
-	if ( item ) {
-		item->type = cJSON_Number;
-		item->valuefloat = num;
-		item->valueint = num;
-	}
-	return item;
-}
+		/* Compose the output: */
+		*out='{';ptr=out+1;if (fmt)*ptr++='\n';*ptr=0;
+		for (i=0;i<numentries;i++)
+		{
+			if (fmt) for (j=0;j<depth;j++) *ptr++='\t';
+			tmplen=strlen(names[i]);memcpy(ptr,names[i],tmplen);ptr+=tmplen;
+			*ptr++=':';if (fmt) *ptr++='\t';
+			strcpy(ptr,entries[i]);ptr+=strlen(entries[i]);
+			if (i!=numentries-1) *ptr++=',';
+			if (fmt) *ptr++='\n';*ptr=0;
+			cJSON_free(names[i]);cJSON_free(entries[i]);
+		}
 
-cJSON *cJSON_CreateString( const char *string )
-{
-	cJSON *item = cJSON_New_Item();
-	if ( item ) {
-		item->type = cJSON_String;
-		item->valuestring = cJSON_strdup( string );
+		cJSON_free(names);cJSON_free(entries);
+		if (fmt) for (i=0;i<depth-1;i++) *ptr++='\t';
+		*ptr++='}';*ptr++=0;
 	}
-	return item;
-}
-
-cJSON *cJSON_CreateArray( void )
-{
-	cJSON *item = cJSON_New_Item();
-	if ( item )
-		item->type = cJSON_Array;
-	return item;
-}
-
-cJSON *cJSON_CreateObject( void )
-{
-	cJSON *item = cJSON_New_Item();
-	if ( item )
-		item->type = cJSON_Object;
-	return item;
+	return out;
 }
 
+/* Get Array size/item / object item. */
+int    cJSON_GetArraySize(cJSON *array)							{cJSON *c=array->child;int i=0;while(c)i++,c=c->next;return i;}
+cJSON *cJSON_GetArrayItem(cJSON *array,int item)				{cJSON *c=array?array->child:0;while (c && item>0) item--,c=c->next; return c;}
+cJSON *cJSON_GetObjectItem(cJSON *object,const char *string)	{cJSON *c=object?object->child:0;while (c && cJSON_strcasecmp(c->string,string)) c=c->next; return c;}
+int cJSON_HasObjectItem(cJSON *object,const char *string)		{return cJSON_GetObjectItem(object,string)?1:0;}
 
-/* Create Arrays. */
+/* Utility for array list handling. */
+static void suffix_object(cJSON *prev,cJSON *item) {prev->next=item;item->prev=prev;}
+/* Utility for handling references. */
+static cJSON *create_reference(cJSON *item) {cJSON *ref=cJSON_New_Item();if (!ref) return 0;memcpy(ref,item,sizeof(cJSON));ref->string=0;ref->type|=cJSON_IsReference;ref->next=ref->prev=0;return ref;}
 
-cJSON *cJSON_CreateIntArray( int64_t *numbers, int count )
-{
-	int i;
-	cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
-	for ( i = 0; a && i < count; ++i ) {
-		n = cJSON_CreateInt( numbers[i] );
-		if ( ! i )
-			a->child = n;
-		else
-			suffix_object( p, n );
-		p = n;
-	}
-	return a;
-}
+/* Add item to array/object. */
+void   cJSON_AddItemToArray(cJSON *array, cJSON *item)						{cJSON *c=array->child;if (!item) return; if (!c) {array->child=item;} else {while (c && c->next) c=c->next; suffix_object(c,item);}}
+void   cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item)	{if (!item) return; if (item->string) cJSON_free(item->string);item->string=cJSON_strdup(string);cJSON_AddItemToArray(object,item);}
+void   cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item)	{if (!item) return; if (!(item->type&cJSON_StringIsConst) && item->string) cJSON_free(item->string);item->string=(char*)string;item->type|=cJSON_StringIsConst;cJSON_AddItemToArray(object,item);}
+void	cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item)						{cJSON_AddItemToArray(array,create_reference(item));}
+void	cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item)	{cJSON_AddItemToObject(object,string,create_reference(item));}
+
+cJSON *cJSON_DetachItemFromArray(cJSON *array,int which)			{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return 0;
+	if (c->prev) c->prev->next=c->next;if (c->next) c->next->prev=c->prev;if (c==array->child) array->child=c->next;c->prev=c->next=0;return c;}
+void   cJSON_DeleteItemFromArray(cJSON *array,int which)			{cJSON_Delete(cJSON_DetachItemFromArray(array,which));}
+cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string) {int i=0;cJSON *c=object->child;while (c && cJSON_strcasecmp(c->string,string)) i++,c=c->next;if (c) return cJSON_DetachItemFromArray(object,i);return 0;}
+void   cJSON_DeleteItemFromObject(cJSON *object,const char *string) {cJSON_Delete(cJSON_DetachItemFromObject(object,string));}
 
-cJSON *cJSON_CreateFloatArray( double *numbers, int count )
-{
-	int i;
-	cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
-	for ( i = 0; a && i < count; ++i ) {
-		n = cJSON_CreateFloat( numbers[i] );
-		if ( ! i )
-			a->child = n;
-		else
-			suffix_object( p, n );
-		p = n;
-	}
-	return a;
-}
+/* Replace array/object items with new ones. */
+void   cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem)		{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) {cJSON_AddItemToArray(array,newitem);return;}
+	newitem->next=c;newitem->prev=c->prev;c->prev=newitem;if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;}
+void   cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem)		{cJSON *c=array->child;while (c && which>0) c=c->next,which--;if (!c) return;
+	newitem->next=c->next;newitem->prev=c->prev;if (newitem->next) newitem->next->prev=newitem;
+	if (c==array->child) array->child=newitem; else newitem->prev->next=newitem;c->next=c->prev=0;cJSON_Delete(c);}
+void   cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem){int i=0;cJSON *c=object->child;while(c && cJSON_strcasecmp(c->string,string))i++,c=c->next;if(c){newitem->string=cJSON_strdup(string);cJSON_ReplaceItemInArray(object,i,newitem);}}
 
-cJSON *cJSON_CreateStringArray( const char **strings, int count )
-{
-	int i;
-	cJSON *n = 0, *p = 0, *a = cJSON_CreateArray();
-	for ( i = 0; a && i < count; ++i ) {
-		n = cJSON_CreateString( strings[i] );
-		if ( ! i )
-			a->child = n;
-		else
-			suffix_object( p, n );
-		p = n;
+/* Create basic types: */
+cJSON *cJSON_CreateNull(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_NULL;return item;}
+cJSON *cJSON_CreateTrue(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_True;return item;}
+cJSON *cJSON_CreateFalse(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_False;return item;}
+cJSON *cJSON_CreateBool(int b)					{cJSON *item=cJSON_New_Item();if(item)item->type=b?cJSON_True:cJSON_False;return item;}
+cJSON *cJSON_CreateNumber(double num)			{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_Number;item->valuedouble=num;item->valueint=(int64_t)num;}return item;}
+cJSON *cJSON_CreateString(const char *string)	{cJSON *item=cJSON_New_Item();if(item){item->type=cJSON_String;item->valuestring=cJSON_strdup(string);if(!item->valuestring){cJSON_Delete(item);return 0;}}return item;}
+cJSON *cJSON_CreateArray(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Array;return item;}
+cJSON *cJSON_CreateObject(void)					{cJSON *item=cJSON_New_Item();if(item)item->type=cJSON_Object;return item;}
+
+/* Create Arrays: */
+cJSON *cJSON_CreateIntArray(const int *numbers,int count)		{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!n){cJSON_Delete(a);return 0;}if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateFloatArray(const float *numbers,int count)	{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!n){cJSON_Delete(a);return 0;}if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateDoubleArray(const double *numbers,int count)	{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateNumber(numbers[i]);if(!n){cJSON_Delete(a);return 0;}if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+cJSON *cJSON_CreateStringArray(const char **strings,int count)	{int i;cJSON *n=0,*p=0,*a=cJSON_CreateArray();for(i=0;a && i<count;i++){n=cJSON_CreateString(strings[i]);if(!n){cJSON_Delete(a);return 0;}if(!i)a->child=n;else suffix_object(p,n);p=n;}return a;}
+
+/* Duplication */
+cJSON *cJSON_Duplicate(cJSON *item,int recurse)
+{
+	cJSON *newitem,*cptr,*nptr=0,*newchild;
+	/* Bail on bad ptr */
+	if (!item) return 0;
+	/* Create new item */
+	newitem=cJSON_New_Item();
+	if (!newitem) return 0;
+	/* Copy over all vars */
+	newitem->type=item->type&(~cJSON_IsReference),newitem->valueint=item->valueint,newitem->valuedouble=item->valuedouble;
+	if (item->valuestring)	{newitem->valuestring=cJSON_strdup(item->valuestring);	if (!newitem->valuestring)	{cJSON_Delete(newitem);return 0;}}
+	if (item->string)		{newitem->string=cJSON_strdup(item->string);			if (!newitem->string)		{cJSON_Delete(newitem);return 0;}}
+	/* If non-recursive, then we're done! */
+	if (!recurse) return newitem;
+	/* Walk the ->next chain for the child. */
+	cptr=item->child;
+	while (cptr)
+	{
+		newchild=cJSON_Duplicate(cptr,1);		/* Duplicate (with recurse) each item in the ->next chain */
+		if (!newchild) {cJSON_Delete(newitem);return 0;}
+		if (nptr)	{nptr->next=newchild,newchild->prev=nptr;nptr=newchild;}	/* If newitem->child already set, then crosswire ->prev and ->next and move on */
+		else		{newitem->child=newchild;nptr=newchild;}					/* Set newitem->child and move to it */
+		cptr=cptr->next;
+	}
+	return newitem;
+}
+
+void cJSON_Minify(char *json)
+{
+	char *into=json;
+	while (*json)
+	{
+		if (*json==' ') json++;
+		else if (*json=='\t') json++;	/* Whitespace characters. */
+		else if (*json=='\r') json++;
+		else if (*json=='\n') json++;
+		else if (*json=='/' && json[1]=='/')  while (*json && *json!='\n') json++;	/* double-slash comments, to end of line. */
+		else if (*json=='/' && json[1]=='*') {while (*json && !(*json=='*' && json[1]=='/')) json++;json+=2;}	/* multiline comments. */
+		else if (*json=='\"'){*into++=*json++;while (*json && *json!='\"'){if (*json=='\\') *into++=*json++;*into++=*json++;}*into++=*json++;} /* string literals, which are \" sensitive. */
+		else *into++=*json++;			/* All other characters. */
 	}
-	return a;
+	*into=0;	/* and null-terminate. */
 }
Index: iperf3-3.0.7/src/cjson.h
===================================================================
--- iperf3-3.0.7.orig/src/cjson.h	2020-01-26 16:42:51.509980713 +0100
+++ iperf3-3.0.7/src/cjson.h	2020-01-26 17:13:23.379823445 +0100
@@ -29,97 +29,122 @@
 #endif
 
 /* cJSON Types: */
-#define cJSON_False 0
-#define cJSON_True 1
-#define cJSON_NULL 2
-#define cJSON_Number 3
-#define cJSON_String 4
-#define cJSON_Array 5
-#define cJSON_Object 6
+#define cJSON_False  (1 << 0)
+#define cJSON_True   (1 << 1)
+#define cJSON_NULL   (1 << 2)
+#define cJSON_Number (1 << 3)
+#define cJSON_String (1 << 4)
+#define cJSON_Array  (1 << 5)
+#define cJSON_Object (1 << 6)
 	
 #define cJSON_IsReference 256
+#define cJSON_StringIsConst 512
 
 /* The cJSON structure: */
 typedef struct cJSON {
-	struct cJSON *next, *prev;	/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
+	struct cJSON *next,*prev;	/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
 	struct cJSON *child;		/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
 
-	int type;			/* The type of the item, as above. */
+	int type;					/* The type of the item, as above. */
 
-	char *valuestring;		/* The item's string, if type==cJSON_String */
-	int64_t valueint;		/* The item's number, if type==cJSON_Number */
-	double valuefloat;		/* The item's number, if type==cJSON_Number */
+	char *valuestring;			/* The item's string, if type==cJSON_String */
+	int64_t valueint;			/* The item's number, if type==cJSON_Number */
+	double valuedouble;			/* The item's number, if type==cJSON_Number */
 
-	char *string;			/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
+	char *string;				/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
 } cJSON;
 
 typedef struct cJSON_Hooks {
-      void *(*malloc_fn)(size_t sz );
-      void (*free_fn)( void *ptr );
+      void *(*malloc_fn)(size_t sz);
+      void (*free_fn)(void *ptr);
 } cJSON_Hooks;
 
 /* Supply malloc, realloc and free functions to cJSON */
-extern void cJSON_InitHooks( cJSON_Hooks* hooks );
+extern void cJSON_InitHooks(cJSON_Hooks* hooks);
 
 
 /* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */
-extern cJSON *cJSON_Parse( const char *value );
+extern cJSON *cJSON_Parse(const char *value);
 /* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */
-extern char *cJSON_Print( cJSON *item );
+extern char  *cJSON_Print(cJSON *item);
 /* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */
-extern char *cJSON_PrintUnformatted( cJSON *item );
+extern char  *cJSON_PrintUnformatted(cJSON *item);
+/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */
+extern char *cJSON_PrintBuffered(cJSON *item,int prebuffer,int fmt);
 /* Delete a cJSON entity and all subentities. */
-extern void cJSON_Delete( cJSON *c );
+extern void   cJSON_Delete(cJSON *c);
 
 /* Returns the number of items in an array (or object). */
-extern int cJSON_GetArraySize( cJSON *array );
+extern int	  cJSON_GetArraySize(cJSON *array);
 /* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */
-extern cJSON *cJSON_GetArrayItem( cJSON *array, int item );
+extern cJSON *cJSON_GetArrayItem(cJSON *array,int item);
 /* Get item "string" from object. Case insensitive. */
-extern cJSON *cJSON_GetObjectItem( cJSON *object, const char *string );
-
+extern cJSON *cJSON_GetObjectItem(cJSON *object,const char *string);
+extern int cJSON_HasObjectItem(cJSON *object,const char *string);
 /* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */
-extern const char *cJSON_GetErrorPtr( void );
+extern const char *cJSON_GetErrorPtr(void);
 	
 /* These calls create a cJSON item of the appropriate type. */
-extern cJSON *cJSON_CreateNull( void );
-extern cJSON *cJSON_CreateTrue( void );
-extern cJSON *cJSON_CreateFalse( void );
-extern cJSON *cJSON_CreateBool( int b );
-extern cJSON *cJSON_CreateInt( int64_t num );
-extern cJSON *cJSON_CreateFloat( double num );
-extern cJSON *cJSON_CreateString( const char *string );
-extern cJSON *cJSON_CreateArray( void );
-extern cJSON *cJSON_CreateObject( void );
+extern cJSON *cJSON_CreateNull(void);
+extern cJSON *cJSON_CreateTrue(void);
+extern cJSON *cJSON_CreateFalse(void);
+extern cJSON *cJSON_CreateBool(int b);
+extern cJSON *cJSON_CreateNumber(double num);
+extern cJSON *cJSON_CreateString(const char *string);
+extern cJSON *cJSON_CreateArray(void);
+extern cJSON *cJSON_CreateObject(void);
 
 /* These utilities create an Array of count items. */
-extern cJSON *cJSON_CreateIntArray( int64_t *numbers, int count );
-extern cJSON *cJSON_CreateFloatArray( double *numbers, int count );
-extern cJSON *cJSON_CreateStringArray( const char **strings, int count );
+extern cJSON *cJSON_CreateIntArray(const int *numbers,int count);
+extern cJSON *cJSON_CreateFloatArray(const float *numbers,int count);
+extern cJSON *cJSON_CreateDoubleArray(const double *numbers,int count);
+extern cJSON *cJSON_CreateStringArray(const char **strings,int count);
 
 /* Append item to the specified array/object. */
-extern void cJSON_AddItemToArray( cJSON *array, cJSON *item );
-extern void cJSON_AddItemToObject( cJSON *object, const char *string, cJSON *item );
+extern void cJSON_AddItemToArray(cJSON *array, cJSON *item);
+extern void	cJSON_AddItemToObject(cJSON *object,const char *string,cJSON *item);
+extern void	cJSON_AddItemToObjectCS(cJSON *object,const char *string,cJSON *item);	/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object */
 /* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */
-extern void cJSON_AddItemReferenceToArray( cJSON *array, cJSON *item );
-extern void cJSON_AddItemReferenceToObject( cJSON *object, const char *string, cJSON *item );
+extern void cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item);
+extern void	cJSON_AddItemReferenceToObject(cJSON *object,const char *string,cJSON *item);
 
 /* Remove/Detatch items from Arrays/Objects. */
-extern cJSON *cJSON_DetachItemFromArray( cJSON *array, int which );
-extern void cJSON_DeleteItemFromArray( cJSON *array, int which );
-extern cJSON *cJSON_DetachItemFromObject( cJSON *object, const char *string );
-extern void cJSON_DeleteItemFromObject( cJSON *object, const char *string );
+extern cJSON *cJSON_DetachItemFromArray(cJSON *array,int which);
+extern void   cJSON_DeleteItemFromArray(cJSON *array,int which);
+extern cJSON *cJSON_DetachItemFromObject(cJSON *object,const char *string);
+extern void   cJSON_DeleteItemFromObject(cJSON *object,const char *string);
 	
 /* Update array items. */
-extern void cJSON_ReplaceItemInArray( cJSON *array, int which, cJSON *newitem );
-extern void cJSON_ReplaceItemInObject( cJSON *object, const char *string, cJSON *newitem );
+extern void cJSON_InsertItemInArray(cJSON *array,int which,cJSON *newitem);	/* Shifts pre-existing items to the right. */
+extern void cJSON_ReplaceItemInArray(cJSON *array,int which,cJSON *newitem);
+extern void cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
+
+/* Duplicate a cJSON item */
+extern cJSON *cJSON_Duplicate(cJSON *item,int recurse);
+/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will
+need to be released. With recurse!=0, it will duplicate any children connected to the item.
+The item->next and ->prev pointers are always zero on return from Duplicate. */
+
+/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */
+/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error. If not, then cJSON_GetErrorPtr() does the job. */
+extern cJSON *cJSON_ParseWithOpts(const char *value,const char **return_parse_end,int require_null_terminated);
+
+extern void cJSON_Minify(char *json);
+
+/* Macros for creating things quickly. */
+#define cJSON_AddNullToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateNull())
+#define cJSON_AddTrueToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateTrue())
+#define cJSON_AddFalseToObject(object,name)		cJSON_AddItemToObject(object, name, cJSON_CreateFalse())
+#define cJSON_AddBoolToObject(object,name,b)	cJSON_AddItemToObject(object, name, cJSON_CreateBool(b))
+#define cJSON_AddNumberToObject(object,name,n)	cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n))
+#define cJSON_AddStringToObject(object,name,s)	cJSON_AddItemToObject(object, name, cJSON_CreateString(s))
+
+/* When assigning an integer value, it needs to be propagated to valuedouble too. */
+#define cJSON_SetIntValue(object,val)			((object)?(object)->valueint=(object)->valuedouble=(val):(val))
+#define cJSON_SetNumberValue(object,val)		((object)?(object)->valueint=(object)->valuedouble=(val):(val))
 
-#define cJSON_AddNullToObject( object, name )		cJSON_AddItemToObject( object, name, cJSON_CreateNull() )
-#define cJSON_AddTrueToObject( object, name )		cJSON_AddItemToObject( object, name, cJSON_CreateTrue() )
-#define cJSON_AddFalseToObject( object, name )		cJSON_AddItemToObject( object, name, cJSON_CreateFalse() )
-#define cJSON_AddIntToObject( object, name, n )		cJSON_AddItemToObject( object, name, cJSON_CreateInt( n ) )
-#define cJSON_AddFloatToObject( object, name, n )	cJSON_AddItemToObject( object, name, cJSON_CreateFloat( n ) )
-#define cJSON_AddStringToObject( object, name, s )	cJSON_AddItemToObject( object, name, cJSON_CreateString( s ) )
+/* Macro for iterating over an array */
+#define cJSON_ArrayForEach(pos, head)			for(pos = (head)->child; pos != NULL; pos = pos->next)
 
 #ifdef __cplusplus
 }
Index: iperf3-3.0.7/src/iperf_util.c
===================================================================
--- iperf3-3.0.7.orig/src/iperf_util.c	2020-01-26 16:42:51.509980713 +0100
+++ iperf3-3.0.7/src/iperf_util.c	2020-01-26 17:15:35.784797716 +0100
@@ -255,10 +255,10 @@
 		j = cJSON_CreateBool(va_arg(argp, int));
 		break;
 		case 'd':
-		j = cJSON_CreateInt(va_arg(argp, int64_t));
+		j = cJSON_CreateNumber(va_arg(argp, int64_t));
 		break;
 		case 'f':
-		j = cJSON_CreateFloat(va_arg(argp, double));
+		j = cJSON_CreateNumber(va_arg(argp, double));
 		break;
 		case 's':
 		j = cJSON_CreateString(va_arg(argp, char *));
Index: iperf3-3.0.7/src/iperf_api.c
===================================================================
--- iperf3-3.0.7.orig/src/iperf_api.c	2020-01-26 16:42:51.509980713 +0100
+++ iperf3-3.0.7/src/iperf_api.c	2020-01-26 17:26:23.281603292 +0100
@@ -494,11 +494,11 @@
 	cJSON_AddStringToObject(test->json_start, "cookie", test->cookie);
         if (test->protocol->id == SOCK_STREAM) {
 	    if (test->settings->mss)
-		cJSON_AddIntToObject(test->json_start, "tcp_mss", test->settings->mss);
+		cJSON_AddNumberToObject(test->json_start, "tcp_mss", test->settings->mss);
 	    else {
 		len = sizeof(opt);
 		getsockopt(test->ctrl_sck, IPPROTO_TCP, TCP_MAXSEG, &opt, &len);
-		cJSON_AddIntToObject(test->json_start, "tcp_mss_default", opt);
+		cJSON_AddNumberToObject(test->json_start, "tcp_mss_default", opt);
 	    }
 	}
     } else if (test->verbose) {
@@ -1092,40 +1092,40 @@
 	    cJSON_AddTrueToObject(j, "tcp");
 	else if (test->protocol->id == Pudp)
 	    cJSON_AddTrueToObject(j, "udp");
-	cJSON_AddIntToObject(j, "omit", test->omit);
+	cJSON_AddNumberToObject(j, "omit", test->omit);
 	if (test->server_affinity != -1)
-	    cJSON_AddIntToObject(j, "server_affinity", test->server_affinity);
+	    cJSON_AddNumberToObject(j, "server_affinity", test->server_affinity);
 	if (test->duration)
-	    cJSON_AddIntToObject(j, "time", test->duration);
+	    cJSON_AddNumberToObject(j, "time", test->duration);
 	if (test->settings->bytes)
-	    cJSON_AddIntToObject(j, "num", test->settings->bytes);
+	    cJSON_AddNumberToObject(j, "num", test->settings->bytes);
 	if (test->settings->blocks)
-	    cJSON_AddIntToObject(j, "blockcount", test->settings->blocks);
+	    cJSON_AddNumberToObject(j, "blockcount", test->settings->blocks);
 	if (test->settings->mss)
-	    cJSON_AddIntToObject(j, "MSS", test->settings->mss);
+	    cJSON_AddNumberToObject(j, "MSS", test->settings->mss);
 	if (test->no_delay)
 	    cJSON_AddTrueToObject(j, "nodelay");
-	cJSON_AddIntToObject(j, "parallel", test->num_streams);
+	cJSON_AddNumberToObject(j, "parallel", test->num_streams);
 	if (test->reverse)
 	    cJSON_AddTrueToObject(j, "reverse");
 	if (test->settings->socket_bufsize)
-	    cJSON_AddIntToObject(j, "window", test->settings->socket_bufsize);
+	    cJSON_AddNumberToObject(j, "window", test->settings->socket_bufsize);
 	if (test->settings->blksize)
-	    cJSON_AddIntToObject(j, "len", test->settings->blksize);
+	    cJSON_AddNumberToObject(j, "len", test->settings->blksize);
 	if (test->settings->rate)
-	    cJSON_AddIntToObject(j, "bandwidth", test->settings->rate);
+	    cJSON_AddNumberToObject(j, "bandwidth", test->settings->rate);
 	if (test->settings->burst)
-	    cJSON_AddIntToObject(j, "burst", test->settings->burst);
+	    cJSON_AddNumberToObject(j, "burst", test->settings->burst);
 	if (test->settings->tos)
-	    cJSON_AddIntToObject(j, "TOS", test->settings->tos);
+	    cJSON_AddNumberToObject(j, "TOS", test->settings->tos);
 	if (test->settings->flowlabel)
-	    cJSON_AddIntToObject(j, "flowlabel", test->settings->flowlabel);
+	    cJSON_AddNumberToObject(j, "flowlabel", test->settings->flowlabel);
 	if (test->title)
 	    cJSON_AddStringToObject(j, "title", test->title);
 	if (test->congestion)
 	    cJSON_AddStringToObject(j, "congestion", test->congestion);
 	if (test->get_server_output)
-	    cJSON_AddIntToObject(j, "get_server_output", iperf_get_test_get_server_output(test));
+	    cJSON_AddNumberToObject(j, "get_server_output", iperf_get_test_get_server_output(test));
 
 	if (test->debug) {
 	    printf("send_parameters:\n%s\n", cJSON_Print(j));
@@ -1224,14 +1224,14 @@
 	i_errno = IEPACKAGERESULTS;
 	r = -1;
     } else {
-	cJSON_AddFloatToObject(j, "cpu_util_total", test->cpu_util[0]);
-	cJSON_AddFloatToObject(j, "cpu_util_user", test->cpu_util[1]);
-	cJSON_AddFloatToObject(j, "cpu_util_system", test->cpu_util[2]);
+	cJSON_AddNumberToObject(j, "cpu_util_total", test->cpu_util[0]);
+	cJSON_AddNumberToObject(j, "cpu_util_user", test->cpu_util[1]);
+	cJSON_AddNumberToObject(j, "cpu_util_system", test->cpu_util[2]);
 	if ( ! test->sender )
 	    sender_has_retransmits = -1;
 	else
 	    sender_has_retransmits = test->sender_has_retransmits;
-	cJSON_AddIntToObject(j, "sender_has_retransmits", sender_has_retransmits);
+	cJSON_AddNumberToObject(j, "sender_has_retransmits", sender_has_retransmits);
 
 	/* If on the server and sending server output, then do this */
 	if (test->role == 's' && test->get_server_output) {
@@ -1275,12 +1275,12 @@
 		    cJSON_AddItemToArray(j_streams, j_stream);
 		    bytes_transferred = test->sender ? sp->result->bytes_sent : sp->result->bytes_received;
 		    retransmits = (test->sender && test->sender_has_retransmits) ? sp->result->stream_retrans : -1;
-		    cJSON_AddIntToObject(j_stream, "id", sp->id);
-		    cJSON_AddIntToObject(j_stream, "bytes", bytes_transferred);
-		    cJSON_AddIntToObject(j_stream, "retransmits", retransmits);
-		    cJSON_AddFloatToObject(j_stream, "jitter", sp->jitter);
-		    cJSON_AddIntToObject(j_stream, "errors", sp->cnt_error);
-		    cJSON_AddIntToObject(j_stream, "packets", sp->packet_count);
+		    cJSON_AddNumberToObject(j_stream, "id", sp->id);
+		    cJSON_AddNumberToObject(j_stream, "bytes", bytes_transferred);
+		    cJSON_AddNumberToObject(j_stream, "retransmits", retransmits);
+		    cJSON_AddNumberToObject(j_stream, "jitter", sp->jitter);
+		    cJSON_AddNumberToObject(j_stream, "errors", sp->cnt_error);
+		    cJSON_AddNumberToObject(j_stream, "packets", sp->packet_count);
 		}
 	    }
 	    if (r == 0 && test->debug) {
@@ -1341,9 +1341,9 @@
 		printf("get_results\n%s\n", cJSON_Print(j));
 	    }
 
-	    test->remote_cpu_util[0] = j_cpu_util_total->valuefloat;
-	    test->remote_cpu_util[1] = j_cpu_util_user->valuefloat;
-	    test->remote_cpu_util[2] = j_cpu_util_system->valuefloat;
+	    test->remote_cpu_util[0] = j_cpu_util_total->valuedouble;
+	    test->remote_cpu_util[1] = j_cpu_util_user->valuedouble;
+	    test->remote_cpu_util[2] = j_cpu_util_system->valuedouble;
 	    result_has_retransmits = j_sender_has_retransmits->valueint;
 	    if (! test->sender)
 		test->sender_has_retransmits = result_has_retransmits;
@@ -1372,7 +1372,7 @@
 			    sid = j_id->valueint;
 			    bytes_transferred = j_bytes->valueint;
 			    retransmits = j_retransmits->valueint;
-			    jitter = j_jitter->valuefloat;
+			    jitter = j_jitter->valuedouble;
 			    cerror = j_errors->valueint;
 			    pcount = j_packets->valueint;
 			    SLIST_FOREACH(sp, &test->streams, streams)
