Skip to content

Commit 7bcabb2

Browse files
Merge pull request #5079 from owen-mc-diffblue/owen/fix-json-parsing-bug
[TG-9218] Fix parsing of escaped characters in json
2 parents 522ae30 + 69aaaf0 commit 7bcabb2

File tree

7 files changed

+95
-9
lines changed

7 files changed

+95
-9
lines changed
Binary file not shown.

jbmc/regression/jbmc/deterministic_assignments_json/StaticValues.java

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ public static void testIntFail() {
1212
public static char asciiCharField = 'a';
1313
public static char hexCharField = '\u0001';
1414
public static char chineseCharField = '字';
15-
public static char specialCharField = '\n';
15+
public static char newLineCharField = '\n';
16+
public static char specialCharField = '\\';
1617
public static char fibCharField = (char) Util.fib(15);
1718
public static void testAsciiCharPass() {
1819
assert asciiCharField == 'a';
@@ -32,12 +33,10 @@ public static void testChineseCharPass() {
3233
public static void testChineseCharFail() {
3334
assert chineseCharField != '字';
3435
}
35-
public static void testSpecialCharPass() {
36-
assert specialCharField == '\n';
37-
}
38-
public static void testSpecialCharFail() {
39-
assert specialCharField != '\n';
40-
}
36+
public static void testNewLineCharPass() { assert newLineCharField == '\n'; }
37+
public static void testNewLineCharFail() { assert newLineCharField != '\n'; }
38+
public static void testSpecialCharPass() { assert specialCharField == '\\'; }
39+
public static void testSpecialCharFail() { assert specialCharField != '\\'; }
4140
public static void testFibCharPass() {
4241
assert fibCharField == 'ɢ';
4342
}

jbmc/regression/jbmc/deterministic_assignments_json/clinit-state.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,10 +343,14 @@
343343
"x":4
344344
}
345345
},
346-
"specialCharField":{
346+
"newLineCharField":{
347347
"@type":"java.lang.Character",
348348
"value":"\n"
349349
},
350+
"specialCharField":{
351+
"@type":"java.lang.Character",
352+
"value":"\\"
353+
},
350354
"hexCharField":{
351355
"@type":"java.lang.Character",
352356
"value":"\u0001"
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
StaticValues.class
3+
--unwind 1 --cp `../../../../scripts/format_classpath.sh . ../../../lib/java-models-library/target/core-models.jar` --static-values clinit-state.json --function StaticValues.testNewLineCharFail
4+
^VERIFICATION FAILED$
5+
^EXIT=10$
6+
^SIGNAL=0$
7+
--
8+
--
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
CORE
2+
StaticValues.class
3+
--unwind 1 --cp `../../../../scripts/format_classpath.sh . ../../../lib/java-models-library/target/core-models.jar` --static-values clinit-state.json --function StaticValues.testNewLineCharPass
4+
^VERIFICATION SUCCESSFUL$
5+
^EXIT=0$
6+
^SIGNAL=0$
7+
--
8+
--

src/json/scanner.l

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
%{
22
// Strictly follows http://www.json.org/
3+
//
4+
// The rule for char and its dependencies is based on
5+
// https://gist.github.com/justjkk/436828
6+
// which is MIT-licensed (retrieved on 2019-09-03)
37
%}
48

59
%option 8bit nodefault
@@ -33,7 +37,11 @@
3337

3438
string \"\"|\"{chars}\"
3539
chars {char}+
36-
char [^\"]|\\\"
40+
unescapedchar [^"\\]
41+
escapedchar \\["\\/bfnrt]
42+
hexdigit [0-9a-fA-F]
43+
unicodechar \\u{hexdigit}{hexdigit}{hexdigit}{hexdigit}
44+
char {unescapedchar}|{escapedchar}|{unicodechar}
3745

3846
number {int}|{int}{frac}|{int}{exp}|{int}{frac}{exp}
3947
int {digit}|{digit19}{digits}|-{digit}|-{digit19}{digits}

unit/json/json_parser.cpp

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,65 @@ SCENARIO("Loading JSON files")
132132
}
133133
}
134134
}
135+
GIVEN("A JSON file containing escaped characters")
136+
{
137+
temporary_filet unicode_json_file("cbmc_unit_json_parser_escaped", ".json");
138+
const std::string unicode_json_path = unicode_json_file();
139+
{
140+
std::ofstream unicode_json_out(unicode_json_path);
141+
unicode_json_out << "{\n"
142+
<< " \"doublequote\": \"\\\"\",\n"
143+
<< " \"backslash\": \"\\\\\",\n"
144+
<< " \"slash\": \"\\/\",\n"
145+
<< " \"backspace\": \"\\b\",\n"
146+
<< " \"formfeed\": \"\\f\",\n"
147+
<< " \"newline\": \"\\n\",\n"
148+
<< " \"return\": \"\\r\",\n"
149+
<< " \"tab\": \"\\t\",\n"
150+
<< " \"several\": \"\\\"\\\\\\/\\b\\f\\n\\r\\t\"\n"
151+
<< "}\n";
152+
}
153+
WHEN("Loading the JSON file with the escaped characters")
154+
{
155+
jsont unicode_json;
156+
const auto unicode_parse_error =
157+
parse_json(unicode_json_path, null_message_handler, unicode_json);
158+
THEN("The JSON file should be parsed correctly")
159+
{
160+
REQUIRE_FALSE(unicode_parse_error);
161+
REQUIRE(unicode_json.is_object());
162+
163+
const json_objectt &json_object = to_json_object(unicode_json);
164+
165+
REQUIRE(json_object.find("doublequote") != json_object.end());
166+
REQUIRE(json_object["doublequote"].value == "\"");
167+
168+
REQUIRE(json_object.find("backslash") != json_object.end());
169+
REQUIRE(json_object["backslash"].value == "\\");
170+
171+
REQUIRE(json_object.find("slash") != json_object.end());
172+
REQUIRE(json_object["slash"].value == "/");
173+
174+
REQUIRE(json_object.find("backspace") != json_object.end());
175+
REQUIRE(json_object["backspace"].value == "\b");
176+
177+
REQUIRE(json_object.find("formfeed") != json_object.end());
178+
REQUIRE(json_object["formfeed"].value == "\f");
179+
180+
REQUIRE(json_object.find("newline") != json_object.end());
181+
REQUIRE(json_object["newline"].value == "\n");
182+
183+
REQUIRE(json_object.find("return") != json_object.end());
184+
REQUIRE(json_object["return"].value == "\r");
185+
186+
REQUIRE(json_object.find("tab") != json_object.end());
187+
REQUIRE(json_object["tab"].value == "\t");
188+
189+
REQUIRE(json_object.find("several") != json_object.end());
190+
REQUIRE(json_object["several"].value == "\"\\/\b\f\n\r\t");
191+
}
192+
}
193+
}
135194
}
136195

137196
TEST_CASE("json equality", "[core][util][json]")

0 commit comments

Comments
 (0)