Skip to content

Recommended usage of SoFullPath exhibits undefined behavior #499

Open
@dodomorandi

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.

Metadata

Assignees

No one assigned

    Labels

    acknowledgedCoin3d team acknowledges this issuebugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions