ukaea/hdc

Constant `HDC` objects can be modified indirectly (may result in undefined behaviour)

Opened this issue · 1 comments

A function accepting a const HDC object can (accidentally) cast away const-ness as in the following example program.

#include <hdc.hpp>

void manipulate_const_hdc(HDC const &in) {
    HDC copy = in;
    copy["new member"] = 1;
}

int main() {
    HDC test;
    test["only member"] = 1;
    test.dump();
    manipulate_const_hdc(test);
    test.dump();
    return 0;
}

Expected behaviour:

The function manipulate_const_hdc gets a constant reference to a HDC object. It shouldn't be able to alter this object as doing so results in undefined behavior, see cppreference.com:

  • A const object is
    - an object whose type is const-qualified, or
    - a non-mutable subobject of a const object.
    Such object cannot be modified: attempt to do so directly is a compile-time error, and attempt to do so indirectly (e.g., by modifying the const object through a reference or pointer to non-const type) results in undefined behavior.

The copy assignment HDC copy = in; should either be prohibited, or it should create a (deep) copy of the HDC object such that the assignment copy["new member"] = 1; doesn't influence the original HDC object.

Actual behaviour:

Output of above test program:

{
        "only member" : 1
}
{
        "new member" : 1,
        "only member" : 1
}

Used version of the HDC library: 0.21.0

Update: there seem to be more issues with const-ness:

  • const_hdc[""] returns a non-const reference to itself
    • In fact HDC get_single(hdc_index_t index) const;, std::map<std::string, HDC> get_children() const;, std::vector<HDC> get_slices() const;, HDC get(size_t index) const;, HDC operator[](size_t index) const;, HDC operator[](const std::string& path) const; all return non-const references to child nodes
  • char* get_buffer() const; provides non-const access to the underlying memory buffer
    • Similar for boost::interprocess::managed_external_buffer get_segment() const;, hdc_map_t* get_children_ptr() const;, hdc_data_t get_data() const;

In all these cases it's very easy for users to write code resulting in undefined behaviour.