Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

A controlled access problem

40 views
Skip to first unread message

Vir Campestris

unread,
Dec 22, 2017, 3:58:08 PM12/22/17
to
I'm crawling through a codebase that's got use-after-free and leaks,
among other interesting features. I'm trying to get smart pointers in -
and they've helped. I've found several use-after-free, and the system
reliability has gone up.

But there's one area that's exercising my mind.

It has a (family of) classes that represent data items. These are called
Fields. They are associated with Nodes, and usually they are a member of
a Node (again, there are several Node classes).

When a Field is updated it makes a call to its parent Node to inform it
that there is new data.

So we have:

class Field
{
Node * parent;
Field(Node* parent): parent(parent) ...

void update(...)
{
...
parent->notify()
}

class Node
{
...

Field foo;
void notify();
}

Just occasionally a Field is not a member datum of a Node, but it is
constructed with a pointer to one. Which is where the fun starts - I'm
not convinced the lifetime is correct.

What I'd like to do is store a weak_ptr<Node> in the field. The trouble
is that during Node construction there can be no shared_ptr, so there's
no valid weak_ptr to store. In this case the constructor must take a raw
Node* pointer.

But I don't want any other code doing this, so I don't want Field(Node*)
to be generally accessible. I do want it accessible to all the Node
class constructors, including where it's a class derived from Node - so
a simple friend won't work.

I've ended up with this. But there must be a better way...

Comments? What follows is a complete sample with two Node types and one
Field.

#include <iostream>
#include <memory>

class Password
{
// Only Datum can create this type.
// Its content is nil, but its access is heavily restricted.
friend class Datum;
};

class Node;

class Gatekeeper
{
// Only Node can call this method. Therefore only Node (via this)
// and Datum (directly) can ever get hold of a Password.
friend class Node;
static constexpr Password const & get();
};

class Datum
{
// Only one of these fields will be filled in.
// if mwParent is expired, and mpParent is null,
// then that is an error.
std::weak_ptr<Node> const mwParent;
Node * const mpParent;

// Allow Gatekeeper to see our Password.
friend Gatekeeper;
static constexpr Password const & password = Password();

public:
// Restrictions on getting a Password mean only members
// of this class and Node can call this.
// Construct given a password and a shared_ptr to a Node.
// This is used by make_shared.
template <typename NodeDerived>
Datum(Password const&, std::shared_ptr<NodeDerived> const & parent)
: mwParent(parent), mpParent(nullptr)
{}

// Construct given a raw pointer to a Node.
// This is used by Node to make its data objects.
template <typename NodeDerived>
Datum(Password const&, NodeDerived * parent)
: mwParent(), mpParent(parent)
{}

template <typename NodeDerived>
static std::shared_ptr<Datum>
make_shared(std::shared_ptr<NodeDerived> const & parent)
{
return std::make_shared<Datum>(password, parent);
}

virtual void notify();
};

// Now we know Datum has a Password we can look at it.
constexpr Password const & Gatekeeper::get() { return Datum::password; }

class Node
{
Datum m1;
protected:
// Allow all Node-derived classes to have a Password.
static constexpr Password const & password = Gatekeeper::get();
public:
// Construct. Anyone can do this.
// Set up our member datum with a pointer to us.
Node(): m1(password, this) {}
virtual void notify()
{
std::cerr << "Node::notify" << std::endl;
};

void shout()
{
std::cerr << "Node::shout1"<< std::endl;
m1.notify();
std::cerr << "Node::shout2"<< std::endl;
}
};

class Node2: public Node
{
Datum m2;
public:
// Construct. Anyone can do this.
// Set up our member datum with a pointer to us.
Node2(): m2(password, this) {}
virtual void notify()
{
std::cerr << "Node2::notify" << std::endl;
};

void shout()
{
std::cerr << "Node2::shout1"<< std::endl;
Node::shout();
m2.notify();
std::cerr << "Node2::shout2"<< std::endl;
}
};

void Datum::notify()
{
if (mpParent)
{
std::cerr << "Datum::notify1" << std::endl;
// The object we are inside must still exist
mpParent->notify();
std::cerr << "Datum::notify2" << std::endl;
}
else
{
std::cerr << "Datum::notify3" << std::endl;
// will crash if the "parent" has died
mwParent.lock()->notify();
std::cerr << "Datum::notify4" << std::endl;
}
}

int main()
{
{
auto foo = std::make_shared<Node2>();

// Construct with a Datum that knows about a Node.
// Anyone can do this,
// but they must have a shared_ptr to the node.
std::shared_ptr<Datum> bar = Datum::make_shared(foo);

foo->shout();
bar->notify();
std::cerr << "All done" << std::endl;
}
}


... and since you've read this far - Merry Christmas / Saturnalia / etc.
Andy

asetof...@gmail.com

unread,
Dec 23, 2017, 2:14:55 PM12/23/17
to
Marry Christmas to all and one Happy New Year

Mr Flibble

unread,
Dec 23, 2017, 3:16:31 PM12/23/17
to
On 23/12/2017 19:14, asetof...@gmail.com wrote:
> Marry Christmas to all and one Happy New Year

Don't peddle your Christian propaganda in this channel kthbai.

/Flibble

--
"Suppose it’s all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What
will Stephen Fry say to him, her, or it?"
"I’d say, bone cancer in children? What’s that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery
that is not our fault. It’s not right, it’s utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates
a world that is so full of injustice and pain. That’s what I would say."

Rick C. Hodgin

unread,
Dec 23, 2017, 7:13:53 PM12/23/17
to
On Saturday, December 23, 2017 at 2:14:55 PM UTC-5, asetof...@gmail.com wrote:
> Marry Christmas to all and one Happy New Year

To you as well.

--
Rick C. Hodgin

Jerry Stuckle

unread,
Dec 23, 2017, 11:19:36 PM12/23/17
to
On 12/23/2017 2:14 PM, asetof...@gmail.com wrote:
> Marry Christmas to all and one Happy New Year
>

Merry Christmas! May yours be a good one.

--
==================
Remove the "x" from my email address
Jerry Stuckle
jstu...@attglobal.net
==================

asetof...@gmail.com

unread,
Dec 25, 2017, 3:51:23 AM12/25/17
to
Merry Christmas and one Happy new year to all
0 new messages