-
Notifications
You must be signed in to change notification settings - Fork 277
Fix for cbmc running out of memory while printing traces using json_ui / target: develop #1814
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix for cbmc running out of memory while printing traces using json_ui / target: develop #1814
Conversation
@@ -11,4 +11,172 @@ Author: Daniel Kroening | |||
/// \file | |||
/// Traces of GOTO Programs | |||
|
|||
#include <cassert> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can be removed now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The commit message isn't very useful.
src/util/ui_message.h
Outdated
@@ -61,14 +61,6 @@ class ui_message_handlert:public message_handlert | |||
int sequence_number, | |||
const source_locationt &location) override; | |||
|
|||
virtual void print( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is in the wrong commit.
src/cbmc/all_properties.cpp
Outdated
result["property"]=json_stringt(id2string(g.first)); | ||
result["description"]=json_stringt(id2string(g.second.description)); | ||
result["status"]=json_stringt(g.second.status_string()); | ||
|
||
if(g.second.status==goalt::statust::FAILURE) | ||
{ | ||
jsont &json_trace=result["trace"]; | ||
convert(bmc.ns, g.second.goto_trace, json_trace, bmc.trace_options()); | ||
json_stream_arrayt &json_trace=result.push_back_stream_array("trace"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(commit for entire commit) This commit should come after the json_goto_trace refactoring.
src/util/json.cpp
Outdated
@@ -133,6 +117,32 @@ void jsont::output_rec(std::ostream &out, unsigned indent) const | |||
} | |||
} | |||
|
|||
void jsont::output_object(std::ostream &out, const objectt &object, unsigned indent) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Some doxygen would be good (sorry that I threw that over to you without docs).
src/util/json_stream.h
Outdated
@@ -10,6 +10,8 @@ Author: Peter Schrammel | |||
#ifndef CPROVER_UTIL_JSON_STREAM_H | |||
#define CPROVER_UTIL_JSON_STREAM_H | |||
|
|||
#include <memory> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this should go into the commit where this file was introduced
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these changes should go into the first commit
src/util/ui_message.cpp
Outdated
@@ -123,51 +122,6 @@ void ui_message_handlert::print( | |||
} | |||
} | |||
|
|||
void ui_message_handlert::print( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems still necessary as XML output hasn't been moved an xml_stream yet.
src/util/ui_message.cpp
Outdated
@@ -6,8 +6,6 @@ Author: Daniel Kroening, kroening@kroening.com | |||
|
|||
\*******************************************************************/ | |||
|
|||
#include "ui_message.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This include should come first.
src/util/ui_message.cpp
Outdated
@@ -17,6 +15,7 @@ Author: Daniel Kroening, kroening@kroening.com | |||
#include "json_expr.h" | |||
#include "json_stream.h" | |||
#include "cout_message.h" | |||
#include "ui_message.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unclear why this file is modified in this commit.
const namespacet &ns=conversion_dependencies.ns; | ||
|
||
irep_idt identifier=step.lhs_object.get_identifier(); | ||
|
||
json_assignment["stepType"]=json_stringt("assignment"); | ||
|
||
if(!location.is_null()) | ||
json_assignment["sourceLocation"]=location; | ||
if(!json_location.is_null()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(comment for entire commit) These changes should be squashed with the previous commit.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suggest to improve the commit message.
4dc26ce
to
c3790b8
Compare
0086ac0
to
0a83f06
Compare
src/util/json.h
Outdated
@@ -109,7 +109,6 @@ class jsont | |||
protected: | |||
void output_rec(std::ostream &, unsigned indent) const; | |||
static void escape_string(const std::string &, std::ostream &); | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unclear why this line is removed
src/util/json_stream.cpp
Outdated
|
||
#include <ostream> | ||
|
||
void json_streamt::output_delimiter() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
there should be some doxygen for all this
src/util/json_stream.h
Outdated
class json_streamt | ||
{ | ||
public: | ||
void close() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doxygen
src/util/json_stream.cpp
Outdated
@@ -52,13 +52,15 @@ json_stream_objectt::json_stream_objectt(std::ostream &out, unsigned indent) | |||
out << '{'; | |||
} | |||
|
|||
/// Create a new JSON array stream. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes to this file should be in the previous commit.
src/util/message.h
Outdated
@@ -232,6 +238,12 @@ class messaget | |||
return func(*this); | |||
} | |||
|
|||
json_stream_arrayt &json_stream() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doxygen
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is there a json_stream_arrayt
variant, but no json_stream_objectt
one?
|
||
source_locationt previous_source_location; | ||
#include "json_goto_trace.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this include should be the first
src/util/json_stream.h
Outdated
@@ -10,6 +10,8 @@ Author: Peter Schrammel | |||
#ifndef CPROVER_UTIL_JSON_STREAM_H | |||
#define CPROVER_UTIL_JSON_STREAM_H | |||
|
|||
#include <memory> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these changes should go into the first commit
src/goto-programs/json_goto_trace.h
Outdated
|
||
typedef struct | ||
{ | ||
jsont &location; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this non-const?
for(const auto &step : goto_trace.steps) | ||
{ | ||
const source_locationt &source_location=step.pc->source_location; | ||
void convert_assert(json_objectt &json_failure, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
doxygen missing throughout these files
conversion_dependenciest &conversion_dependencies) | ||
{ | ||
const goto_trace_stept& step=conversion_dependencies.step; | ||
jsont &location=conversion_dependencies.location; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why is this non-const?
@NlightNFotis, there's a compiliation error: https://travis-ci.org/diffblue/cbmc/jobs/339128397#L1550 |
Also, cpplint and clang-format are complaining. Be careful to reformat the changes in each commit separately. |
src/goto-programs/json_goto_trace.h
Outdated
|
||
#include <util/json_expr.h> | ||
#include <util/arith_tools.h> | ||
#include <util/config.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a couple of header files that can be put into the cpp file.
268a8f5
to
7c8ea18
Compare
This should be ready to review, this only needs the clang format changes to be squashed to their appropriate commits. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The PR talks about fixing an out-of-memory problem, but then in the middle of the PR suddenly there is a refactoring commit as well. Lots of seemingly unnecessary whitespace changes. All of that makes reviewing extremely hard.
My main concern, however, is the core API that is not at all self-documenting. I get the problem that it is trying to solve, but it's very hard to tell whether that solution is actually fit for purpose. See details in my comments.
src/util/json.cpp
Outdated
if(o_it!=object.begin()) | ||
out << ','; | ||
|
||
out << '\n'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't the newline also be conditional on o_it!=object.beginn()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, because an object always starts with an opening brace, after which we put a newline (code snippet factored out from lines 69-85 above).
src/util/json.cpp
Outdated
out << '"'; | ||
jsont::escape_string(key, out); | ||
out << '"'; | ||
out << ": "; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not a big deal, but out << "\": ";
would also do the trick, wouldn't it?
src/util/json.h
Outdated
|
||
std::string value; | ||
|
||
friend class json_stream_objectt; | ||
friend class json_stream_arrayt; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remote friends are bad.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Seems unnecessary to have them.
src/util/json_stream.cpp
Outdated
{ | ||
current->close(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be honest, that's a very strange piece of code. It seems to be extremely context-dependent and far from side-effect free.
src/util/json_stream.cpp
Outdated
{ | ||
out << '\n' << std::string(indent*2, ' '); | ||
out << ']'; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The constructor does out << '['
so I'd expect this to be done in a destructor (otherwise the constructor shouldn't be doing the opening bracket).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is exactly what it is doing (by calling close() which, in turn, calls output_finalizer).
src/util/json_stream.cpp
Outdated
return create_current_array(); | ||
} | ||
|
||
/// Overloaded version of the push_back_stream_object, that |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nit pick: no comma before "that"
src/util/json_stream.h
Outdated
/// This approach was necessary to fix some issues with | ||
/// CBMC running out of memory when it had to print some | ||
/// huge traces for some programs. | ||
class json_streamt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only public operation is close
- that's truly weird. Please create a meaningful API, which might have virtual ...(...) = 0;
members - but at least it would explain how to use this thingy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only public facility that this base class provides is close().
output_current and output_finalizer should be made abstract.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this has happened? Maybe it has, but they are all protected
so I have no idea what is the public interface of (children of) json_streamt
.
src/util/json_stream.h
Outdated
/// JSON object. | ||
/// \param key: The key to be looked up inside the | ||
/// attributes of the JSON object. | ||
jsont &operator[](const std::string &key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How does this fit in a "stream" class?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It allows mixing streamed and non-streamed json elements. The API enforces that the parent of a streamed element must always be a streamed element.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does it even make sense to mix them? Or is my above thought that a json_streamt
is actually also some form of jsont
that actually holds data?!
src/cbmc/all_properties.cpp
Outdated
@@ -207,18 +207,18 @@ void bmc_all_propertiest::report(const cover_goalst &cover_goals) | |||
case ui_message_handlert::uit::JSON_UI: | |||
{ | |||
json_objectt json_result; | |||
json_arrayt &result_array=json_result["result"].make_array(); | |||
json_arrayt &result_array = json_result["result"].make_array(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Whitespace changes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These whitespace changes are unnecessary.
trace_optionst trace_options = trace_optionst::default_options); | ||
const namespacet &ns, | ||
const goto_tracet &goto_trace, | ||
json_arrayT &dest_array, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does this need to be a template argument?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be able to use both the streaming and the object version.
8bb7f83
to
6544980
Compare
trace_optionst trace_options = trace_optionst::default_options); | ||
const namespacet &ns, | ||
const goto_tracet &goto_trace, | ||
json_arrayT &dest_array, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be able to use both the streaming and the object version.
src/cbmc/all_properties.cpp
Outdated
@@ -207,18 +207,18 @@ void bmc_all_propertiest::report(const cover_goalst &cover_goals) | |||
case ui_message_handlert::uit::JSON_UI: | |||
{ | |||
json_objectt json_result; | |||
json_arrayt &result_array=json_result["result"].make_array(); | |||
json_arrayt &result_array = json_result["result"].make_array(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These whitespace changes are unnecessary.
src/cbmc/bmc_cover.cpp
Outdated
@@ -369,7 +369,7 @@ bool bmc_covert::operator()() | |||
json_objectt &result=tests_array.push_back().make_object(); | |||
if(bmc.options.get_bool_option("trace")) | |||
{ | |||
jsont &json_trace=result["trace"]; | |||
jsont &json_trace = result["trace"]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unnecessary.
@@ -33,20 +33,20 @@ void convert( | |||
jsont &dest, | |||
trace_optionst trace_options) | |||
{ | |||
json_arrayt &dest_array=dest.make_array(); | |||
json_arrayt &dest_array = dest.make_array(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The changes in this file are unnecessary.
src/util/json.cpp
Outdated
if(o_it!=object.begin()) | ||
out << ','; | ||
|
||
out << '\n'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, because an object always starts with an opening brace, after which we put a newline (code snippet factored out from lines 69-85 above).
src/util/json_stream.cpp
Outdated
current = | ||
std::unique_ptr<json_streamt>(new json_stream_objectt(out, indent + 1)); | ||
return static_cast<json_stream_objectt &>(*current); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree. There is some doxygen work to be done to explain how things fit together.
src/util/json_stream.h
Outdated
class json_stream_objectt; | ||
class json_stream_arrayt; | ||
|
||
/// New class whose aim is to stream newly created JSON |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This "new class" will soon be an "old class" ;)
src/util/json_stream.h
Outdated
/// This approach was necessary to fix some issues with | ||
/// CBMC running out of memory when it had to print some | ||
/// huge traces for some programs. | ||
class json_streamt |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The only public facility that this base class provides is close().
output_current and output_finalizer should be made abstract.
src/util/json_stream.h
Outdated
/// JSON object. | ||
/// \param key: The key to be looked up inside the | ||
/// attributes of the JSON object. | ||
jsont &operator[](const std::string &key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It allows mixing streamed and non-streamed json elements. The API enforces that the parent of a streamed element must always be a streamed element.
src/util/message.h
Outdated
@@ -209,7 +209,17 @@ class messaget | |||
return *this; | |||
} | |||
|
|||
mstreamt &operator << (const json_objectt &data) | |||
mstreamt &operator<<(const jsont &data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change seems unnecessary.
3e9a845
to
fdb4576
Compare
4e39f6d
to
e74cdf6
Compare
3cedf1d
to
8049ef1
Compare
I have added one last commit that attempts to fix the I will write a lengthier report about what was happening and why this is necessary later. |
8049ef1
to
63140dd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, @NlightNFotis, this looks good now. Please update the TG bump.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Various comments below, with the definitive blocker of using std::cout
(and thus iostream) in a header file.
I'm still not sure I'm on the right track: do we now have multiple classes that serve one and the same purpose, but differ in how output is implemented? Does this mix data representation and behaviour? Are you solving an original design deficiency in that a jsont
took care of its own output by adding a variant that takes care of its own output in a different way? Shouldn't output
just never have been a member function of jsont
? Isn't this one of the prototypical situations to use the visitor pattern? Even more so as jsont
is the root of a nice family of classes, and also a very much bounded one so that it wouldn't be necessary to add more members to a visitor (as is sort of the case for anything based on irept
)?
virtual json_stream_arrayt &get_json_stream() | ||
{ | ||
UNREACHABLE; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please explain why this isn't get_json_stream() = 0;
or marked protected?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I change it to get_json_stream() = 0;
then I get compilation errors that some variables, such as message_handler
in line 189 of graphml.cpp
can not be initialised to an abstract type. I understand that this happens because other members of the hierarchy, like null_message_handlert
are not redefining get_json_stream()
, a now pure virtual function.
If it's marked protected
, that creates problems with the interaction with the class mstreamt
in the same file (message.h
, line 184), particularly with the method json_stream()
in line 244, which contains the statement return message.message_handler->get_json_stream();
, which can not work with get_json_stream()
being protected.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I change it to
get_json_stream() = 0;
then I get compilation errors that some variables, such asmessage_handler
in line 189 ofgraphml.cpp
can not be initialised to an abstract type. I understand that this happens because other members of the hierarchy, likenull_message_handlert
are not redefiningget_json_stream()
, a now pure virtual function.
To me, this looks like a prime example of why compile-time errors are preferable over runtime errors: in my opinion, that just means that null_message_handlert
needs to be fixed.
src/util/message.h
Outdated
@@ -16,6 +16,7 @@ Author: Daniel Kroening, kroening@kroening.com | |||
|
|||
#include "invariant.h" | |||
#include "json.h" | |||
#include "json_stream.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe a forward declaration class json_stream_arrayt;
would suffice.
@@ -106,7 +106,6 @@ class jsont | |||
return it->second; | |||
} | |||
|
|||
protected: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If you remove this, then also the public
in line 123 is redundant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@NlightNFotis, this shouldn't be removed. Only move the function that is required to the public section.
src/util/json_stream.cpp
Outdated
if(child_stream) | ||
{ | ||
child_stream->close(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't this prone to attempts of closing a closed file? child_stream
is not reset.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Closing closed files is not a practical issue here because json_streamt only wraps the actual stream (that could be a file). json_streamt never closes that stream - that's in the realm of the user of json_streamt. However, to avoid confusion, I would assign child_stream = nullptr here and put appropriate PRECONDITIONS to make sure that there is no double-close (which is indeed a sign of a programming error).
output_delimiter(); | ||
jsont::output_key(out, key); | ||
return create_child_stream_object(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the purpose of all these push_back_stream*
functions ("Add a JSON ..." -- to what?) as none of them are invoked anywhere in this commit, and why aren't they just a single one in the parent class? I understand that they have different return types, but is that actually necessary (as anything done to those return values can be resolved to the right child class via virtual tables)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be very inconvenient to let the user cast to json_stream_arrayt and json_stream_objectt in order to use their respective interfaces (objects and arrays are quite different things).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this fits with my overall comment: there seems to be a strong case for re-architecting here to use a visitor rather than this proposed design of inheritance.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@tautschnig, could you please explain how 'use a visitor' would contribute to a solution in this context?
Inheritance is used here because json_stream_arrayt and json_stream_objectt are both json streams, which share common functionality, namely flushing the data. If this is considered too little to justify a base class the common code can be duplicated in the respective derived classes at the cost of complicating the logic to flush the stream and to enforce the single-stream-at-a-time invariant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In my opinion, there should be one class that knows how to stream jsont
. That class would be the visitor. It has methods that know how to stream a json_arrayt
or json_objectt
(and json_numbert
, json_stringt
, etc.).
/// array stream. | ||
/// Provided for compatibility with `jsont`. | ||
/// \return a new empty, non-streaming JSON object | ||
jsont &push_back() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do you need compatibility with jsont
? Are you saying that this some sort of replacement for jsont
? Please tell me that I'm wrong.
src/util/json_stream.h
Outdated
/// JSON object. | ||
/// \param key: The key to be looked up inside the | ||
/// attributes of the JSON object. | ||
jsont &operator[](const std::string &key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does it even make sense to mix them? Or is my above thought that a json_streamt
is actually also some form of jsont
that actually holds data?!
src/util/message.h
Outdated
@@ -232,6 +238,12 @@ class messaget | |||
return func(*this); | |||
} | |||
|
|||
json_stream_arrayt &json_stream() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is there a json_stream_arrayt
variant, but no json_stream_objectt
one?
src/util/ui_message.h
Outdated
@@ -10,9 +10,14 @@ Author: Daniel Kroening, kroening@kroening.com | |||
#ifndef CPROVER_UTIL_UI_MESSAGE_H | |||
#define CPROVER_UTIL_UI_MESSAGE_H | |||
|
|||
#include <memory> | |||
#include <iostream> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope. Not in a header file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@NlightNFotis, the implementation of the constructor must go into the .cpp file.
src/util/ui_message.h
Outdated
: _ui(uit::PLAIN), time(timestampert::make(timestampert::clockt::NONE)) | ||
: _ui(uit::PLAIN), | ||
time(timestampert::make(timestampert::clockt::NONE)), | ||
out(std::cout), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First, there seems to be no point of even having a std::ostream
member as there is a single function that relies on it, and no way to setting it to any other value. Second, this has no place in a header file.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, out
is used many, many times in the .cpp file. Eventually, assigning out
should be the only use of std::cout
in the codebase.
The implementation of the constructor must be moved back into the cpp file.
@@ -106,7 +106,6 @@ class jsont | |||
return it->second; | |||
} | |||
|
|||
protected: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@NlightNFotis, this shouldn't be removed. Only move the function that is required to the public section.
output_delimiter(); | ||
object["array_element"].output_rec(out, indent + 1); | ||
object.clear(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are actually quite similar. The only difference is that array elements don't have keys.
src/util/json_stream.cpp
Outdated
if(child_stream) | ||
{ | ||
child_stream->close(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Closing closed files is not a practical issue here because json_streamt only wraps the actual stream (that could be a file). json_streamt never closes that stream - that's in the realm of the user of json_streamt. However, to avoid confusion, I would assign child_stream = nullptr here and put appropriate PRECONDITIONS to make sure that there is no double-close (which is indeed a sign of a programming error).
output_delimiter(); | ||
jsont::output_key(out, key); | ||
return create_child_stream_object(); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It would be very inconvenient to let the user cast to json_stream_arrayt and json_stream_objectt in order to use their respective interfaces (objects and arrays are quite different things).
{ | ||
output_child_stream(); | ||
output_finalizer(); | ||
open = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No. open
is the state of this
not child_stream
. You can create and close many child streams sequentially (timewise), e.g. for each element in an array or each property in an object). The invariant is that there can only be at most child stream at a time.
src/util/json_stream.h
Outdated
{ | ||
} | ||
|
||
bool open; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@NlightNFotis, it seems that open
requires explanation.
src/util/ui_message.h
Outdated
@@ -10,9 +10,14 @@ Author: Daniel Kroening, kroening@kroening.com | |||
#ifndef CPROVER_UTIL_UI_MESSAGE_H | |||
#define CPROVER_UTIL_UI_MESSAGE_H | |||
|
|||
#include <memory> | |||
#include <iostream> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@NlightNFotis, the implementation of the constructor must go into the .cpp file.
src/util/ui_message.h
Outdated
: _ui(uit::PLAIN), time(timestampert::make(timestampert::clockt::NONE)) | ||
: _ui(uit::PLAIN), | ||
time(timestampert::make(timestampert::clockt::NONE)), | ||
out(std::cout), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, out
is used many, many times in the .cpp file. Eventually, assigning out
should be the only use of std::cout
in the codebase.
The implementation of the constructor must be moved back into the cpp file.
63140dd
to
4cf7dfc
Compare
Hi @tautschnig. I think your concerns have been addressed. Is it possible that you take another look and let me know if there's anything more you want to be done, else give it the green light? Thanks for your time, |
To what extent has #1814 (comment):
been addressed? Anyone is free to override my non-approval, but I do maintain that the architecture here is flawed and that implementing a different form of output by inheriting and overriding the data representation is wrong. |
@tautschnig As the person who had the initial problem -- would it help if I had a review? |
@martin-cs Your reviews are always welcome! It may very well be the case that an urgent solution is required and I thus invite overrides to my non-approval. Any maybe my suggested architecture is also flawed. I'm always open to input. |
4cf7dfc
to
496476a
Compare
Introduce a new json object class that streams the object immediately to an output instead of building the object in memory and then output it to the stream.
Refactor the templated convert function with switch statements that handle different instructions to dispatch to functions that are specialised per instruction.
496476a
to
123be20
Compare
@tautschnig @peterschrammel I have been made aware that there have been offline discussions regarding the architectural changes in this PR, and the disagreements have been resolved. Can you both take a look to let me know if everything is alright, and if yes, possibly merge it as well? @peterschrammel The associated testgen PR is also passing with no problems |
My apologies for having been dense and not fully understanding the problem this was trying to solve. It took an out-of-band chat with @peterschrammel to get me on track: it was not clear to me that constructing the Here is what I would have done: make |
This is a port of #1767 to
develop
(instead ofgoto-analyzer-develop
as requested by @peterschrammel and @martin-cs . Below is the message of the original PR:There has been a bug reported to us where cbmc would run out of memory while creating a huge json object in memory to report the traces with. This is changing the tracing report facility to use a new json class that streams the objects immediately as created, and therefore fixes the issue.