Skip to content

Commit 3640541

Browse files
committed
Merge PR bitcoin#32 from branch 'nul-not-special' of git://github.com/ryanofsky/univalue into merge
Conflicts: Makefile.am lib/univalue_read.cpp test/.gitignore
2 parents 89bb073 + fd32d1a commit 3640541

8 files changed

+48
-23
lines changed

Makefile.am

+7-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ libunivalue_la_LDFLAGS = \
2020
-no-undefined
2121
libunivalue_la_CXXFLAGS = -I$(top_srcdir)/include
2222

23-
TESTS = test/unitester
23+
TESTS = test/unitester test/no_nul
2424

2525
GENBIN = gen/gen$(BUILD_EXEEXT)
2626
GEN_SRCS = gen/gen.cpp
@@ -47,6 +47,11 @@ test_test_json_LDADD = libunivalue.la
4747
test_test_json_CXXFLAGS = -I$(top_srcdir)/include
4848
test_test_json_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
4949

50+
test_no_nul_SOURCES = test/no_nul.cpp
51+
test_no_nul_LDADD = libunivalue.la
52+
test_no_nul_CXXFLAGS = -I$(top_srcdir)/include
53+
test_no_nul_LDFLAGS = -static $(LIBTOOL_APP_LDFLAGS)
54+
5055
TEST_FILES = \
5156
$(TEST_DATA_DIR)/fail10.json \
5257
$(TEST_DATA_DIR)/fail11.json \
@@ -82,6 +87,7 @@ TEST_FILES = \
8287
$(TEST_DATA_DIR)/fail39.json \
8388
$(TEST_DATA_DIR)/fail40.json \
8489
$(TEST_DATA_DIR)/fail41.json \
90+
$(TEST_DATA_DIR)/fail42.json \
8591
$(TEST_DATA_DIR)/fail3.json \
8692
$(TEST_DATA_DIR)/fail4.json \
8793
$(TEST_DATA_DIR)/fail5.json \

include/univalue.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,10 @@ class UniValue {
124124
std::string write(unsigned int prettyIndent = 0,
125125
unsigned int indentLevel = 0) const;
126126

127+
bool read(const char *raw, size_t len);
127128
bool read(const char *raw);
128129
bool read(const std::string& rawStr) {
129-
return read(rawStr.c_str());
130+
return read(rawStr.data(), rawStr.size());
130131
}
131132

132133
private:
@@ -240,7 +241,7 @@ enum jtokentype {
240241
};
241242

242243
extern enum jtokentype getJsonToken(std::string& tokenVal,
243-
unsigned int& consumed, const char *raw);
244+
unsigned int& consumed, const char *raw, const char *end);
244245
extern const char *uvTypeName(UniValue::VType t);
245246

246247
static inline bool jsonTokenIsValue(enum jtokentype jtt)

lib/univalue.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ static bool validNumStr(const string& s)
104104
{
105105
string tokenVal;
106106
unsigned int consumed;
107-
enum jtokentype tt = getJsonToken(tokenVal, consumed, s.c_str());
107+
enum jtokentype tt = getJsonToken(tokenVal, consumed, s.data(), s.data() + s.size());
108108
return (tt == JTOK_NUMBER);
109109
}
110110

lib/univalue_read.cpp

+27-19
Original file line numberDiff line numberDiff line change
@@ -43,21 +43,21 @@ static const char *hatoui(const char *first, const char *last,
4343
}
4444

4545
enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
46-
const char *raw)
46+
const char *raw, const char *end)
4747
{
4848
tokenVal.clear();
4949
consumed = 0;
5050

5151
const char *rawStart = raw;
5252

53-
while ((*raw) && (json_isspace(*raw))) // skip whitespace
53+
while (raw < end && (json_isspace(*raw))) // skip whitespace
5454
raw++;
5555

56-
switch (*raw) {
57-
58-
case 0:
56+
if (raw >= end)
5957
return JTOK_NONE;
6058

59+
switch (*raw) {
60+
6161
case '{':
6262
raw++;
6363
consumed = (raw - rawStart);
@@ -127,40 +127,40 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
127127
numStr += *raw; // copy first char
128128
raw++;
129129

130-
if ((*first == '-') && (!json_isdigit(*raw)))
130+
if ((*first == '-') && (raw < end) && (!json_isdigit(*raw)))
131131
return JTOK_ERR;
132132

133-
while ((*raw) && json_isdigit(*raw)) { // copy digits
133+
while (raw < end && json_isdigit(*raw)) { // copy digits
134134
numStr += *raw;
135135
raw++;
136136
}
137137

138138
// part 2: frac
139-
if (*raw == '.') {
139+
if (raw < end && *raw == '.') {
140140
numStr += *raw; // copy .
141141
raw++;
142142

143-
if (!json_isdigit(*raw))
143+
if (raw >= end || !json_isdigit(*raw))
144144
return JTOK_ERR;
145-
while ((*raw) && json_isdigit(*raw)) { // copy digits
145+
while (raw < end && json_isdigit(*raw)) { // copy digits
146146
numStr += *raw;
147147
raw++;
148148
}
149149
}
150150

151151
// part 3: exp
152-
if (*raw == 'e' || *raw == 'E') {
152+
if (raw < end && (*raw == 'e' || *raw == 'E')) {
153153
numStr += *raw; // copy E
154154
raw++;
155155

156-
if (*raw == '-' || *raw == '+') { // copy +/-
156+
if (raw < end && (*raw == '-' || *raw == '+')) { // copy +/-
157157
numStr += *raw;
158158
raw++;
159159
}
160160

161-
if (!json_isdigit(*raw))
161+
if (raw >= end || !json_isdigit(*raw))
162162
return JTOK_ERR;
163-
while ((*raw) && json_isdigit(*raw)) { // copy digits
163+
while (raw < end && json_isdigit(*raw)) { // copy digits
164164
numStr += *raw;
165165
raw++;
166166
}
@@ -177,13 +177,16 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
177177
string valStr;
178178
JSONUTF8StringFilter writer(valStr);
179179

180-
while (true) {
180+
while (raw < end) {
181181
if ((unsigned char)*raw < 0x20)
182182
return JTOK_ERR;
183183

184184
else if (*raw == '\\') {
185185
raw++; // skip backslash
186186

187+
if (raw >= end)
188+
return JTOK_ERR;
189+
187190
switch (*raw) {
188191
case '"': writer.push_back('\"'); break;
189192
case '\\': writer.push_back('\\'); break;
@@ -196,7 +199,8 @@ enum jtokentype getJsonToken(string& tokenVal, unsigned int& consumed,
196199

197200
case 'u': {
198201
unsigned int codepoint;
199-
if (hatoui(raw + 1, raw + 1 + 4, codepoint) !=
202+
if (raw + 1 + 4 >= end ||
203+
hatoui(raw + 1, raw + 1 + 4, codepoint) !=
200204
raw + 1 + 4)
201205
return JTOK_ERR;
202206
writer.push_back_u(codepoint);
@@ -246,7 +250,7 @@ enum expect_bits {
246250
#define setExpect(bit) (expectMask |= EXP_##bit)
247251
#define clearExpect(bit) (expectMask &= ~EXP_##bit)
248252

249-
bool UniValue::read(const char *raw)
253+
bool UniValue::read(const char *raw, size_t size)
250254
{
251255
clear();
252256

@@ -257,10 +261,11 @@ bool UniValue::read(const char *raw)
257261
unsigned int consumed;
258262
enum jtokentype tok = JTOK_NONE;
259263
enum jtokentype last_tok = JTOK_NONE;
264+
const char* end = raw + size;
260265
do {
261266
last_tok = tok;
262267

263-
tok = getJsonToken(tokenVal, consumed, raw);
268+
tok = getJsonToken(tokenVal, consumed, raw, end);
264269
if (tok == JTOK_NONE || tok == JTOK_ERR)
265270
return false;
266271
raw += consumed;
@@ -437,10 +442,13 @@ bool UniValue::read(const char *raw)
437442
} while (!stack.empty ());
438443

439444
/* Check that nothing follows the initial construct (parsed above). */
440-
tok = getJsonToken(tokenVal, consumed, raw);
445+
tok = getJsonToken(tokenVal, consumed, raw, end);
441446
if (tok != JTOK_NONE)
442447
return false;
443448

444449
return true;
445450
}
446451

452+
bool UniValue::read(const char *raw) {
453+
return read(raw, strlen(raw));
454+
}

test/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
unitester
22
test_json
3+
no_nul
34

45
*.trs
56
*.log

test/fail42.json

37 Bytes
Binary file not shown.

test/no_nul.cpp

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
#include "univalue.h"
2+
3+
int main (int argc, char *argv[])
4+
{
5+
char buf[] = "___[1,2,3]___";
6+
UniValue val;
7+
return val.read(buf + 3, 7) ? 0 : 1;
8+
}

test/unitester.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ static const char *filenames[] = {
113113
"fail39.json", // invalid unicode: only second half of surrogate pair
114114
"fail40.json", // invalid unicode: broken UTF-8
115115
"fail41.json", // invalid unicode: unfinished UTF-8
116+
"fail42.json", // valid json with garbage following a nul byte
116117
"fail3.json",
117118
"fail4.json", // extra comma
118119
"fail5.json",

0 commit comments

Comments
 (0)