Recommended usage of SoFullPath exhibits undefined behavior #499
Description
This is a quote from SoFullPath.cpp doc:
Since the SoFullPath is derived from SoPath and contains no private data, you can cast SoPath instances to the SoFullPath type.
This suggestion is wrong because, as also explained here, you cannot instantiate a base class and cast it to a derived type, even if there are no additional fields in the derived class.
The issue is caught by the undefined behavior sanitizer using GCC 12.2.1 (probably even with older version) with the following snippet:
#include <Inventor/SoFullPath.h>
#include <cstdio>
int main() {
auto path = static_cast<SoFullPath*>(new SoPath(10));
std::printf("%d", path->getLength());
// Nope, ~SoPath() is protected. Must leak...
// delete static_cast<SoPath*>(path);
}
The code, assuming the snippet is called so_full_path_casting.cpp
, can be compiled with:
g++ -Wall -Wextra -Wpedantic -fsanitize=undefined so_full_path_casting.cpp -o so_full_path_casting -lCoin
It is also impossible to correctly destruct and deallocate the instance, as noted in the comment, but that is another can of worms (the issue is even more clear if you try to use a std::unique_ptr
instead of the new
, because it won't compile).
I generally like to be constructive when raising an issue, proposing possible solutions or at least some ideas. In this case I have to say sorry because I don't see a good approach: other projects depends on this exact behavior (because it is the recommended way), therefore changing the architecture of SoPath
and SoFullPath
could easily lead to subtle breaking changes (and exhibit effects of UB, which seem to be silent in this case). From my perspective, the simplest approach is extremely effective from a technical point of view: making the constructor of SoFullPath
public in order to make things work in the most intuitive way. However, it's hard to perceive this kind of changes from other projects, it will probably go unnoticed. On the other hand, if you explicitly opt for a noticeable breaking change (like, for instance, totally removing SoFullPath
), people will be probably angry.
As already said, I don't see a good approach, I hope you are better than me at finding one. In any case, thank you for your efforts.