@@ -35,6 +35,8 @@ use std::os::unix::process::ExitStatusExt;
35
35
use std:: path:: PathBuf ;
36
36
use std:: process:: { Child , ChildStdout } ;
37
37
38
+ const RESULT_ITEM_PREFIX : & str = " {\n \" result\" :" ;
39
+
38
40
/// A parser item is a top-level unit of output from the CBMC json format.
39
41
/// See the parser for more information on how they are processed.
40
42
#[ derive( Debug , Deserialize ) ]
@@ -57,6 +59,17 @@ pub enum ParserItem {
57
59
} ,
58
60
}
59
61
62
+ /// Struct that is equivalent to `ParserItem::Result`.
63
+ ///
64
+ /// Note: this struct is only used to provide better error messages when there
65
+ /// are issues deserializing a `ParserItem::Result`. See `Parser::parse_item`
66
+ /// for more details.
67
+ #[ allow( unused) ]
68
+ #[ derive( Debug , Deserialize ) ]
69
+ struct ResultStruct {
70
+ result : Vec < Property > ,
71
+ }
72
+
60
73
/// Struct that represents a single property in the set of CBMC results.
61
74
///
62
75
/// Note: `reach` is not part of the parsed data, but it's useful to annotate
@@ -285,7 +298,7 @@ pub struct TraceValue {
285
298
pub name : String ,
286
299
pub binary : Option < String > ,
287
300
pub data : Option < TraceData > ,
288
- pub width : Option < u8 > ,
301
+ pub width : Option < u32 > ,
289
302
}
290
303
291
304
/// Enum that represents a trace data item.
@@ -420,6 +433,25 @@ impl<'a, 'b> Parser<'a, 'b> {
420
433
if let Ok ( item) = result_item {
421
434
return item;
422
435
}
436
+ // If we failed to parse a `ParserItem::Result` earlier, we will get
437
+ // this error message when we attempt to parse it using the complete
438
+ // string:
439
+ // ```
440
+ // thread '<unnamed>' panicked at 'called `Result::unwrap()` on an `Err` value:
441
+ // Error("data did not match any variant of untagged enum ParserItem", line: 0, column: 0)'
442
+ // ```
443
+ // This error message doesn't provide information about what went wrong
444
+ // while parsing due to `ParserItem` being an untagged enum. A more
445
+ // informative error message will be produced if we attempt to
446
+ // deserialize it into a struct. The attempt will still fail, but it
447
+ // shouldn't be hard to debug with that information. The same strategy
448
+ // can be used for other `ParserItem` variants, but they're normally
449
+ // easier to debug.
450
+ if string_without_delimiter. starts_with ( RESULT_ITEM_PREFIX ) {
451
+ let result_item: Result < ResultStruct , _ > =
452
+ serde_json:: from_str ( string_without_delimiter) ;
453
+ result_item. unwrap ( ) ;
454
+ }
423
455
let complete_string = & self . input_so_far [ 0 ..self . input_so_far . len ( ) ] ;
424
456
let result_item: Result < ParserItem , _ > = serde_json:: from_str ( complete_string) ;
425
457
result_item. unwrap ( )
@@ -681,4 +713,45 @@ mod tests {
681
713
serde_json:: from_str ( prop_id_string) ;
682
714
let _prop_id = prop_id_result. unwrap ( ) ;
683
715
}
716
+
717
+ #[ test]
718
+ fn check_trace_value_deserialization_works ( ) {
719
+ let data = format ! (
720
+ r#"{{
721
+ "binary": "{:0>1000}",
722
+ "data": "0",
723
+ "name": "integer",
724
+ "type": "unsigned __CPROVER_bitvector[960]",
725
+ "width": 960
726
+ }}"# ,
727
+ 0
728
+ ) ;
729
+ let trace_value: Result < TraceValue , _ > = serde_json:: from_str ( & data) ;
730
+ assert ! ( trace_value. is_ok( ) ) ;
731
+ }
732
+
733
+ /// Checks that a valid CBMC "result" item can be deserialized into a
734
+ /// `ParserItem` or `ResultStruct`.
735
+ #[ test]
736
+ fn check_result_deserialization_works ( ) {
737
+ let data = r#"{
738
+ "result": [
739
+ {
740
+ "description": "assertion failed: 1 > 2",
741
+ "property": "long_function_name.assertion.1",
742
+ "sourceLocation": {
743
+ "column": "16",
744
+ "file": "/home/ubuntu/file.rs",
745
+ "function": "long_function_name",
746
+ "line": "815"
747
+ },
748
+ "status": "SUCCESS"
749
+ }
750
+ ]
751
+ }"# ;
752
+ let parser_item: Result < ParserItem , _ > = serde_json:: from_str ( & data) ;
753
+ let result_struct: Result < ResultStruct , _ > = serde_json:: from_str ( & data) ;
754
+ assert ! ( parser_item. is_ok( ) ) ;
755
+ assert ! ( result_struct. is_ok( ) ) ;
756
+ }
684
757
}
0 commit comments