-
Notifications
You must be signed in to change notification settings - Fork 75
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
Yaml Crash Problem WIP #282
Conversation
Ok, after debugging around in Yaml on Ubuntu I am left without a clue. What I know:
I see nothing that can cause the class to get messed up just by making a call....no other logic involved that I can see. The curious thing is that it crashes only when called from within our code (their unit tests run just fine), and only in debug mode on Linux. To me this sounds like the compiler got something wrong. |
I can try another compiler but it seems like we had this crash before going to a newer compiler. So I am left without a fix. I will look around and see if there is another Yaml parser package that we could substitute. |
Ok, here is what I am finding:
At this point, I am ready to try the libyaml parser. I will do this in parallel so that I don't take out yaml-cpp until I am sure libyaml will work for us. Sorry to be so verbose on this topic but I wanted to document the decisions. |
this should fix yaml-cpp bug, gtest might need to match Debug/Release of project
determine by CMAKE_BUILD_TYPE, IDEs will need to rebuild,fix if Debug/Release is switched
external/bootstrap.cmake
Outdated
@@ -47,36 +49,15 @@ execute_process(COMMAND ${CMAKE_COMMAND} | |||
if(result) | |||
message(FATAL_ERROR "CMake step for Third Party builds failed: ${result}") | |||
endif() | |||
if(MSVC) | |||
# for MSVC builds we need to build both Release and Debug builds |
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 we should not do this (double Release, Debug build). The IDE should fix that, or one can call Clean and Rebuild..
This way, the CI build time is artificially doubled
@dkeeney can you push the path that forces yaml-cpp to be built with Release, please? I'm not sure I've implemented it well |
I am mothballing this PR. I will come back to it when there is less high priority work to do. |
I tried that....it still crashes if the main program is Debug. |
I am in the process of testing with RapidYaml. Finding a few snags preventing me from pushing it to github. Trying to find a work-around. This parser is so new that there are a few rough edges yet but I like it so far. If I cannot get this to work, there is another yaml parser I could try. So, lets keep #282 since it is what I am working on. |
that's even better new, cool! Glad you like the parser. So let's see how well it fares for you. |
I think I hit a wall with RapidYaml. Exceptions are the killer. If there are any kind of error RapidYaml expect your entire program to die. I tried various ways to try and capture the error and throw an exception but it does not work. Most of the code is C code so it does not really support exceptions. But they should at least attempt to return an error code ... but they do not. I suspect they cannot guarantee that their internal data structures are still valid after an error is detected. Anyway, I posted my review in their issues page in hopes that they will address this. |
Ok, where to go from here... My current thinking is to attempt to use libyaml. This is a SAX parser which means it gives callbacks for each thing it parses so you can build your own structure. It is a little extra code but not bad. But in the mean time, I would like to take advantage of the work I did on RapidYaml and replace our current yaml code with one that does not use the Spec. It can still be yam-cpp but its interface is encapsulated into a single .cpp file, |
This push contains the code I am experimenting with. It contains all three yaml parsers although only one at a time is compiled. None of them actually compile at this point.
The objectives of this project are:
|
I am taking a break and traveling up to San Jose to see my grandson this weekend. I will continue work when I return. |
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 David, esp. for all the work with testing 3 yaml parsers!
I like the idea of hiding yaml parsing under Value.hpp, hope you get one of the parsers working (let's see if rapidYaml replies; do we need to handle crashes in yaml parsing, or could we just hard fail on error?)
@@ -29,6 +29,7 @@ set($ENV{HTM_CPP} ${REPOSITORY_DIR}) | |||
# | |||
option(FORCE_CPP11 "Force compiler to use C++11 standard." OFF) | |||
option(FORCE_BOOST "Force compiler to install and use Boost." OFF) | |||
set(YAML_PARSER "yamlcpp" CACHE STRING "Specify the YAML parser to use 'yamlcpp', 'RapidYaml', 'libyaml', default 'yamlcpp'." ) |
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 know this is a WIP, eventually we'll want to have just 1 parser.
src/CMakeLists.txt
Outdated
htm/ntypes/Value.cpp | ||
htm/ntypes/Value-yamlcpp.cpp | ||
htm/ntypes/Value-rapidyaml.cpp | ||
htm/ntypes/Value-libyaml.cpp |
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.
TODO, only one will be used when finalized
src/htm/engine/Spec.hpp
Outdated
NTA_BasicType dataType; | ||
// 1 = scalar; > 1 = array o fixed sized; 0 = array of unknown size | ||
// TODO: should be size_t? Serialization issues? | ||
size_t count; |
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.
guess it's size_t for the >1
case, likely we'd never exceed an UInt, but saving a few bytes in serialized state is imho not worth a change (so I'd leave as is)
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.
size_t in Spec
I did not make that change. That is in the master.
But it does not matter, eventually I hope to remove Spec if I can.
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 know, I was replying to the TODO (which was new?)
const char *s1 = "10"; | ||
vm.parse(s1); | ||
EXPECT_TRUE(vm.isScalar()); | ||
UInt32 u = vm.as<UInt32>(); |
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.
do we need to keep the value map with separate parse, "as" steps, or could we use just vm.as<T>("str")
?
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.
do we need to keep the value map with separate parse, "as" steps, or could we use just vm.as("str") ?
I don't follow the question. Are you proposing the argument to the as( arg ) be a string to be parsed? I guess it could. This would only be useful for things like default values from the Spec stored as Yaml or JSON strings. But perhaps it might have use elsewhere.
The test is checking the ability of the root of the tree to be a scalar. Normally it is a map or a sequence but could be any of the three or empty. If you know ahead of time that a string contains a scalar then you don't need to parse...just use std:: conversion functions. But if you don't know then you will need to check if the parsed node is a scalar before using the as( ).
There are lots of tests yet to be added.
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.
Actually, the reason I started with tests of the root being a scalar is that RapidYaml required the root node to be a map or sequence. If you parsed a string that was really a scalar it would create a sequence and add the scalar as the first node. So you could not tell the difference between "123" and "[123]". Scalar operations on the root would fail. So I had to find a work-around.
Yaml-cpp allowed the root to be scalar. libyaml does not have a node, you have to create it yourself...which is what our Value class is.
|
||
vm.parse("- 1"); | ||
EXPECT_TRUE(vm.isSequence()); | ||
u = vm[0].as<UInt32>(); |
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 "- 1" just fail? and why "1" is in [0], then "-" is then in [1]..parser working right-to-left?
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 "- 1" just fail? and why "1" is in [0], then "-" is then in [1]..parser working right-to-left?
In YAML, a leading "- " (a dash followed by a space) means this is an element of a sequence.
The construct vm[0] means give me the first element of the sequence which should be the scaler "1".
Thanks, I've reviewed the recent changes. Have a nice trip! |
The key thing to evaluate is Value.hpp since this should define the functions available for the parameter facility. ValueMap is the root and Value is a node in the parsed tree. ValueMap is actually just a Value object as well. Right now all parameter handling is flat. In other words, the root is a map and all children are scalars. I want to be able to allow just about any structure that could be described by Yaml or JSON to be used as the set of parameters. Some of the new parsers will require it. The inspiration for the feature set is taken from the YAML::Node in https://github.com/jbeder/yaml-cpp/wiki/Tutorial. I have yet to implement the operator= which will allow individual nodes to be created and modified after, or instead of, the parse. Originally I was going to just use YAML::Node or a subclass of it, but that would lock us into yaml-cpp. So that is why we need the Value class to hide the implementation. |
Well, this means the app terminates with no chance of catching and continuing. Makes it rather hard to do negative tests because the test stops. If you had a string like "abc" and tried to use vm.as() the program dies. |
pushing this PR so that I can switch to Linux. I want to see if this fixes the Yaml crash problem in Linux debug mode. |
I am getting some unexpected failures while locally testing my Yaml changes.
How could these errors have gotten into the master without being detected by the CI? |
I don't know the cause yet but I cannot locally run the python tests using the command
The C++ unit tests do run successfully but when it gets to the python tests it give me the following:
|
This was a false alarm. |
Continued in PR #715 |
I was getting these by a) forgetting to uninstall some older htm.core version in the pyenv, b) some part compiled with different c++/py compiler/version. |
Deleting the old versions of htm.core and and starting over with a new branch seemed to fix it. |
This PR is to investigate the problem where Yaml crashes when running in debug mode on Linux.
No fix yet.
Fixes #218