-
Notifications
You must be signed in to change notification settings - Fork 46
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
Use templates for the base types to factorize code #186
Conversation
fa30c2f
to
4f3de95
Compare
I need to update libmatroska to build with this branch |
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.
Doesn't merge with the current master at the moment. Can you please rebase? I'll review then.
As soon as it works in libmatroska :) |
4f3de95
to
074b33d
Compare
742314a
to
d0af2a8
Compare
ebml/EbmlElement.h
Outdated
@@ -220,6 +277,7 @@ class EBML_DLL_API EbmlCallbacks { | |||
inline EbmlElement & NewElement() const { return Create(); } | |||
/// is infinite/unknown size allowed | |||
inline bool CanHaveInfiniteSize() const { return CanInfinite; } | |||
virtual const bool HasDefault() const { return 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.
Compiler warning:
lib/libebml/ebml/EbmlElement.h:280:17: warning: 'const' type qualifier on return type has no effect [-Wignored-qualifiers]
virtual const bool HasDefault() const { return false; }
Just change it to virtual bool HasDefault() const
both here & in EbmlCallbacksDefault
.
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.
Additional compiler warning:
lib/libebml/ebml/EbmlElement.h:262:20: warning: 'libebml::EbmlCallbacks' has virtual functions but non-virtual destructor [-Wnon-virtual-dtor]
class EBML_DLL_API EbmlCallbacks {
Adding a simple
virtual ~EbmlCallbacks() {}
seems to get rid of them, but at the cost of a compiler error in various later source files, e.g. EbmlDummy.cpp
:
lib/libebml/src/EbmlDummy.cpp:13:1: fatal error: constexpr variable cannot have non-literal type 'const EbmlCallbacks'
DEFINE_EBML_CLASS_ORPHAN(EbmlDummy, 0xFF, 1, "DummyElement")
^
lib/libebml/ebml/EbmlElement.h:150:60: note: expanded from macro 'DEFINE_EBML_CLASS_ORPHAN'
#define DEFINE_EBML_CLASS_ORPHAN(x,id,idl,name) DEFINE_xxx_CLASS_ORPHAN(x,id,idl,name,GetEbmlGlobal_Context)
^
lib/libebml/ebml/EbmlElement.h:145:38: note: expanded from macro 'DEFINE_xxx_CLASS_ORPHAN'
constexpr const EbmlCallbacks x::ClassInfos(x::Create, Id_##x, false, name, Context_##x); \
^
lib/libebml/ebml/EbmlElement.h:274:13: note: 'EbmlCallbacks' is not literal because it has a user-provided destructor
virtual ~EbmlCallbacks() {}
^
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 fixed both. It's odd I don't get these warnings in clang.
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.
Hmmm the warning: 'libebml::EbmlCallbacks' has virtual functions but non-virtual destructor [-Wnon-virtual-dtor]
warning is still there in revision 5b434b7.
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.
BTW, I also compile with clang++
, using the following warning/error options:
-Wall -Wno-comment -Wfatal-errors -fstack-protector-strong -O3 -g3 -std=c++17 -Wnon-virtual-dtor -Wextra -Wno-missing-field-initializers -Wunused -Wpedantic -Woverloaded-virtual -Wshadow -Qunused-arguments -Wno-self-assign -Wno-mismatched-tags -Wno-inconsistent-missing-override -Wno-potentially-evaluated-expression -Wno-extra-semi
Pretty sure that -Wnon-virtual-dtor
turns on this particular warning.
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.
Fixed. I also added #195 to make these issues more visible in the future.
3e87c7c
to
5b434b7
Compare
5b434b7
to
d2a17a3
Compare
I still get an error:
|
I forgot to push the lastest version of the libmatroska counterpart: Matroska-Org/libmatroska#134 |
Thanks. Compiles now. But there are a ton of issues from crashing due to null pointer access to use of uninitialized values. I've fixed some of them locally, will try to look into the others over the next couple of days. Definitely not ready for merging yet. |
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 at least three issues that I found. I couldn't really fix them as I didn't understand your new structure enough. Please look into the following:
nullptr arguments not checked
Operators & functions taking pointers are dereferencing the pointers, leading to invalid memory access or exceptions being thrown when nullptr
is given as an argument. This immediately happens in operator ==
in both EbmlString
& EbmlUnicodeString
. I don't have the stack trace at hand, but both functions were called with a nullptr
arg, causing std::string
/std::wstring
to throw an std::logic_error
.
Not sure what the right way to handle nullptr
is. Two possibilities:
- Always return
false
, as in "must not be used that way, cannot be equal" - Check if stored
Value
is empty & returntrue
if so, as in "no string and empty string are the same"
Another function that comes to mind here is EbmlElementDefaultSameStorage::IsSmallerThan
.
reads from uninitialized values
Using valgrind I can see tons of errors of the form of making decisions based on uninitialized Value
member variables, mostly in EbmlUInteger
. This is unsurprising as the EbmlElementDefaultSameStorage
and EbmlElementDefaultStorage
don't initialize their Value
member variable, neither statically in the class definition, nor in the constructor. The constructor in the original EbmlUInteger
class from before the changes initialized their value member to the class's default value according to the specs, or to 0 (or the variable's equivalent) if there was no default.
This definitely affects EbmlUInteger
, EbmlSInteger
, EbmlFloat
, EbmlDate
as they have trivial member variables, which are only initialized if the code requests it.
It likely does not affect EbmlString
, EbmlUnicodeString
, EbmlBinary
, EbmlCrc32
as those use non-trivial types which do get initialized via their default constructor.
Please take a look at those issues.
d2a17a3
to
da4da9b
Compare
I simplified the PR to not include the code factorization to make it easier to spot the regressions. The libmatroska counterpart is still needed with this PR. |
da4da9b
to
f797165
Compare
I added some tests for strings with and without a default value and did hit some null pointer dereferencing. It was using the default value when there isn't one. It may also be the valgrind issues you saw. The default value should never be used if the default class says it has no default value. So I think this branch should be safe now. |
280eddf
to
19ad33a
Compare
I cannot test the branch in its current form. I need to be able to query an existing element if it has a default value. In 1.x I can do that via However, this current iteration doesn't have a way to retrieve the |
19ad33a
to
836d4ae
Compare
0eac624
to
288a6b6
Compare
I reworked the code further. I am now testing default values on an There is no longer a type that holds the default value if there is one. There's one |
Thanks. With
Here's what the same code compiled with branch
Another interesting (but wrong) effect is that the cues suddenly contain "cue codec state" elements, even if the file doesn't contain any codec state elements! They're just… there suddenly. Again I'm comparing files created with the same mkvmerge code, just compiled with different libebml/libmatroska releases. It seems that the initial values are still not initialized. Running the mkvmerge from
I definitely do not have those warnings when running valgrind on the "good" mkvmerge compiled against v1.x. These types of decisions based on uninitialized values could easily explain the behavior mentioned above with the "cue codec state" elements suddenly appearing. |
Thanks for all the tests. If the header is broken it's definitely something that can be tested in libebml. I'll give this a try. Can you check that #204 works for you ? It will help reduce the scope of this PR. |
Done! #204 is fine & can be merged. |
It's mandatory since 8494914 and always stored in the EbmlElement.
So the default value is hardcoded in the class semantic info and not set in the constructor. A new EbmlElement subclass is created for EbmlElement types that may have a default value. An IsSameValue() method is added to compare an element to a value. This is used by the EbmlElementDefault class to tell if the element value is the same as the default when there is one.
288a6b6
to
d4f9bc8
Compare
I found the issue. The old constructor with a default value would initialize the element to its default value. IMO the element should not be initialized until it's manually done. If not it has its default value to use or should not be used at all. For I went with the forced initialization. Only for elements with a default value, the other ones should not be used without setting a value (or their size is 0 = default value for the type). Now it passes the test from #206. |
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! Now it passes all of my tests as well. Nice work!
Can be merged (along with the corresponding branch for libmatroska).
Awesome. Thanks for all the testing. |
A lot of the logic is the same between classes. We can factorize the code once we have factorized the storage (and initialization) types in a template.
The default value is moved to a EbmlCallbacksDefault class for the types that can have a default value. So the default value is not copied in each instance of every object.
This was done on top of #173 but maybe it works on its own.