Skip to content
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

randv (and related classes) don't use RAII #2

Open
AnthonyVH opened this issue Jun 12, 2018 · 2 comments
Open

randv (and related classes) don't use RAII #2

AnthonyVH opened this issue Jun 12, 2018 · 2 comments

Comments

@AnthonyVH
Copy link

AnthonyVH commented Jun 12, 2018

When a crave::randv object is constructed with a non-nullptr value for the parent pointer, it registers itself with said parent (through randv_base::add_base_child). However, upon destruction it doesn't deregister itself from the parent. This causes dangling pointers and the undefined behavior that comes with it when rand_base::next() is called on the parent (so far I've seen SIGSERV and "abstract virtual called").

Furthermore, since there's copy constructors defined for the randv_base and randv types, move construction and assignment are both implicitly disabled. Just "thinking out loud", it seems to me that when a parent class is moved, it should be able to call some sort of "move_parent()" on the randv child objects. Such move_parent functionality would be the equivalent of remove_base_child (which currently doesn't exist) followed by add_base_child. This move_parent could then also be called by a user's custom objects where appropriate.

Similar things can most likely be said about rand_obj and its add_obj_child function (although I didn't check this thoroughly yet).

Below is a minimalistic example that triggers UB through derefencing pointers to destructed objects. I know crave::rand_vec exists, but I don't see why this example using std::vector shouldn't be able to work if the above issues are solved.

#include <crave/ConstrainedRandom.hpp>

#include <cstdint>
#include <iostream>
#include <vector>

struct custom_item : public crave::rand_obj {
  using base_type = crave::rand_obj;

  custom_item (crave::rand_obj * parent = nullptr)
    : base_type(parent), vectorSize_(this)
  {
    constraint(0 < vectorSize_() && vectorSize_() <= 10);
  }

  virtual bool next () override {
    bool const result = base_type::next();
    post_randomize();
    return result;
  }

  virtual void post_randomize () {
    items_.clear();
    items_.reserve(vectorSize_);
    for (std::size_t count = 0; count < vectorSize_; ++count) {
      items_.emplace_back(this);
      items_.back().next();
    }
  }

  crave::randv<std::size_t> vectorSize_;
  std::vector<crave::randv<int>> items_ = {};
};

std::ostream & operator<< (std::ostream & os, custom_item const & obj) {
  os << "elements [" << obj.vectorSize_ << "]: ";
  for (auto const & entry : obj.items_) { os << entry << ' '; }
  return os;
}

int main () {
  crave::init("crave.cfg");
  crave::set_global_seed(1234567890); // Raises SIGSERV.
  //crave::set_global_seed(2234567890); // Raises abstract virtual called.

  custom_item anItem;

  for (int i = 0; i < 5; i++) {
    CHECK(anItem.next());
    std::cout << anItem << '\n';
  }
}
@hoangmle
Copy link
Member

We did not intend to support manipulation of the randv/rand_obj object tree from user code, but it would have been useful to detach objects on their destruction to prevent such unwanted UBs. May I ask you to continue your evaluation on the experimental API (which does support some form of RAII if I remember correctly) since the 2.0 one is going to be deprecated soon?

As for your example, I would just use a vector<int> and a single randv<int> to fill the vector with generated values in a loop. This also helps to avoid constructing/deleting multiple randv at run-time.

@AnthonyVH
Copy link
Author

Sure thing, I'll try any new experiments against the experimental API.

Using a single randv<int> to populate the vector would definitely be more efficient in this case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants