mirror of
https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git
synced 2025-07-18 11:19:10 +00:00
Fix dupe callbacks in VaultAddChildNode
This code called back into the python vault operation thingy, which deletes itself. So, anytime we got dupe CBs, there was a use-after-free error. Nasty crashes. I tightened up the CB management, threw away some weird faux-management mess, and squashed some potential silent bugs.
This commit is contained in:
@ -246,18 +246,27 @@ struct VaultAgeInitTrans {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AddChildNodeFetchTrans {
|
class AddChildNodeTrans {
|
||||||
FVaultAddChildNodeCallback callback;
|
FVaultAddChildNodeCallback callback;
|
||||||
void * cbParam;
|
void * cbParam;
|
||||||
ENetError result;
|
ENetError result;
|
||||||
std::atomic<long> opCount;
|
std::atomic<long> opCount;
|
||||||
|
|
||||||
AddChildNodeFetchTrans()
|
void CompleteOp();
|
||||||
: callback(nil), cbParam(nil), result(kNetSuccess), opCount(0) { }
|
|
||||||
|
|
||||||
AddChildNodeFetchTrans(FVaultAddChildNodeCallback _callback, void * _param)
|
public:
|
||||||
|
AddChildNodeTrans()
|
||||||
|
: callback(nullptr), cbParam(nullptr), result(kNetSuccess), opCount(0) { }
|
||||||
|
|
||||||
|
AddChildNodeTrans(FVaultAddChildNodeCallback _callback, void * _param)
|
||||||
: callback(_callback), cbParam(_param), result(kNetSuccess), opCount(0) { }
|
: callback(_callback), cbParam(_param), result(kNetSuccess), opCount(0) { }
|
||||||
|
|
||||||
|
void AddOp() { ++opCount; }
|
||||||
|
|
||||||
|
static void VaultNodeAdded (
|
||||||
|
ENetError result,
|
||||||
|
void * param
|
||||||
|
);
|
||||||
static void VaultNodeFetched (
|
static void VaultNodeFetched (
|
||||||
ENetError result,
|
ENetError result,
|
||||||
void * param,
|
void * param,
|
||||||
@ -994,18 +1003,38 @@ void VaultAgeInitTrans::AgeInitCallback (
|
|||||||
|
|
||||||
/*****************************************************************************
|
/*****************************************************************************
|
||||||
*
|
*
|
||||||
* AddChildNodeFetchTrans
|
* AddChildNodeTrans
|
||||||
*
|
*
|
||||||
***/
|
***/
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void AddChildNodeFetchTrans::VaultNodeRefsFetched (
|
void AddChildNodeTrans::CompleteOp() {
|
||||||
|
if ((--opCount) == 0) {
|
||||||
|
if (callback)
|
||||||
|
callback(result, cbParam);
|
||||||
|
delete this; // commit hara-kiri
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void AddChildNodeTrans::VaultNodeAdded(
|
||||||
|
ENetError result,
|
||||||
|
void* param
|
||||||
|
) {
|
||||||
|
AddChildNodeTrans* trans = static_cast<AddChildNodeTrans*>(param);
|
||||||
|
if (IS_NET_ERROR(result))
|
||||||
|
trans->result = result;
|
||||||
|
trans->CompleteOp();
|
||||||
|
}
|
||||||
|
|
||||||
|
//============================================================================
|
||||||
|
void AddChildNodeTrans::VaultNodeRefsFetched (
|
||||||
ENetError result,
|
ENetError result,
|
||||||
void * param,
|
void * param,
|
||||||
NetVaultNodeRef * refs,
|
NetVaultNodeRef * refs,
|
||||||
unsigned refCount
|
unsigned refCount
|
||||||
) {
|
) {
|
||||||
AddChildNodeFetchTrans * trans = (AddChildNodeFetchTrans *)param;
|
AddChildNodeTrans * trans = (AddChildNodeTrans *)param;
|
||||||
|
|
||||||
if (IS_NET_ERROR(result)) {
|
if (IS_NET_ERROR(result)) {
|
||||||
trans->result = result;
|
trans->result = result;
|
||||||
@ -1015,45 +1044,27 @@ void AddChildNodeFetchTrans::VaultNodeRefsFetched (
|
|||||||
FetchNodesFromRefs(
|
FetchNodesFromRefs(
|
||||||
refs,
|
refs,
|
||||||
refCount,
|
refCount,
|
||||||
AddChildNodeFetchTrans::VaultNodeFetched,
|
AddChildNodeTrans::VaultNodeFetched,
|
||||||
param,
|
param,
|
||||||
&incFetchCount
|
&incFetchCount
|
||||||
);
|
);
|
||||||
trans->opCount += incFetchCount;
|
trans->opCount += incFetchCount;
|
||||||
}
|
}
|
||||||
|
trans->CompleteOp();
|
||||||
// Make the callback now if there are no nodes to fetch, or if error
|
|
||||||
if (!(--trans->opCount)) {
|
|
||||||
if (trans->callback)
|
|
||||||
trans->callback(
|
|
||||||
trans->result,
|
|
||||||
trans->cbParam
|
|
||||||
);
|
|
||||||
delete trans;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//============================================================================
|
//============================================================================
|
||||||
void AddChildNodeFetchTrans::VaultNodeFetched (
|
void AddChildNodeTrans::VaultNodeFetched (
|
||||||
ENetError result,
|
ENetError result,
|
||||||
void * param,
|
void * param,
|
||||||
NetVaultNode * node
|
NetVaultNode * node
|
||||||
) {
|
) {
|
||||||
::VaultNodeFetched(result, param, node);
|
::VaultNodeFetched(result, param, node);
|
||||||
|
|
||||||
AddChildNodeFetchTrans * trans = (AddChildNodeFetchTrans *)param;
|
AddChildNodeTrans * trans = (AddChildNodeTrans *)param;
|
||||||
|
|
||||||
if (IS_NET_ERROR(result))
|
if (IS_NET_ERROR(result))
|
||||||
trans->result = result;
|
trans->result = result;
|
||||||
|
trans->CompleteOp();
|
||||||
if (!(--trans->opCount)) {
|
|
||||||
if (trans->callback)
|
|
||||||
trans->callback(
|
|
||||||
trans->result,
|
|
||||||
trans->cbParam
|
|
||||||
);
|
|
||||||
delete trans;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1737,9 +1748,6 @@ void VaultAddChildNode (
|
|||||||
FVaultAddChildNodeCallback callback,
|
FVaultAddChildNodeCallback callback,
|
||||||
void * param
|
void * param
|
||||||
) {
|
) {
|
||||||
// Make sure we only do the callback once
|
|
||||||
bool madeCallback = false;
|
|
||||||
|
|
||||||
// Too much of the client relies on the assumption that the node will be immediately
|
// Too much of the client relies on the assumption that the node will be immediately
|
||||||
// associated with its parent. THIS SUCKS, because there's no way to guarantee the
|
// associated with its parent. THIS SUCKS, because there's no way to guarantee the
|
||||||
// association won't be circular (the db checks this in a comprehensive way).
|
// association won't be circular (the db checks this in a comprehensive way).
|
||||||
@ -1748,14 +1756,14 @@ void VaultAddChildNode (
|
|||||||
// This directly affects: New clothing items added to the avatar outfit folder,
|
// This directly affects: New clothing items added to the avatar outfit folder,
|
||||||
// new chronicle entries in some ages, and I'm sure several other situations.
|
// new chronicle entries in some ages, and I'm sure several other situations.
|
||||||
|
|
||||||
|
AddChildNodeTrans * trans = nullptr;
|
||||||
if (RelVaultNodeLink * parentLink = s_nodes.Find(parentId)) {
|
if (RelVaultNodeLink * parentLink = s_nodes.Find(parentId)) {
|
||||||
RelVaultNodeLink * childLink = s_nodes.Find(childId);
|
RelVaultNodeLink * childLink = s_nodes.Find(childId);
|
||||||
if (!childLink) {
|
if (!childLink) {
|
||||||
childLink = new RelVaultNodeLink(false, ownerId, childId, new RelVaultNode);
|
childLink = new RelVaultNodeLink(false, ownerId, childId, new RelVaultNode);
|
||||||
childLink->node->SetNodeId_NoDirty(childId);
|
childLink->node->SetNodeId_NoDirty(childId);
|
||||||
s_nodes.Add(childLink);
|
s_nodes.Add(childLink);
|
||||||
}
|
} else if (ownerId) {
|
||||||
else if (ownerId) {
|
|
||||||
childLink->ownerId = ownerId;
|
childLink->ownerId = ownerId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1770,14 +1778,17 @@ void VaultAddChildNode (
|
|||||||
// callback now with error code
|
// callback now with error code
|
||||||
if (callback)
|
if (callback)
|
||||||
callback(kNetErrCircularReference, param);
|
callback(kNetErrCircularReference, param);
|
||||||
}
|
// I don't really care what Eric thinks, if we believe it's a circular reference, it's evil
|
||||||
else if (childLink->node->IsParentOf(parentId, 255)) {
|
// to report a failure, then send it to the server anyway! That's just a bug WAITING
|
||||||
|
// to be uncovered, and I don't want to deal with it!
|
||||||
|
return;
|
||||||
|
} else if (childLink->node->IsParentOf(parentId, 255)) {
|
||||||
LogMsg(kLogDebug, L"Node relationship would be circular: p:%u, c:%u", parentId, childId);
|
LogMsg(kLogDebug, L"Node relationship would be circular: p:%u, c:%u", parentId, childId);
|
||||||
// callback now with error code
|
// callback now with error code
|
||||||
if (callback)
|
if (callback)
|
||||||
callback(kNetErrCircularReference, param);
|
callback(kNetErrCircularReference, param);
|
||||||
}
|
return;
|
||||||
else {
|
} else {
|
||||||
NetVaultNodeRef refs[] = {
|
NetVaultNodeRef refs[] = {
|
||||||
{ parentId, childId, ownerId }
|
{ parentId, childId, ownerId }
|
||||||
};
|
};
|
||||||
@ -1786,66 +1797,52 @@ void VaultAddChildNode (
|
|||||||
ARRAY(unsigned) existingNodeIds;
|
ARRAY(unsigned) existingNodeIds;
|
||||||
|
|
||||||
BuildNodeTree(refs, arrsize(refs), &newNodeIds, &existingNodeIds);
|
BuildNodeTree(refs, arrsize(refs), &newNodeIds, &existingNodeIds);
|
||||||
|
|
||||||
|
trans = new AddChildNodeTrans(callback, param);
|
||||||
if (!childLink->node->GetNodeType() || !parentLink->node->GetNodeType()) {
|
if (!childLink->node->GetNodeType() || !parentLink->node->GetNodeType()) {
|
||||||
// One or more nodes need to be fetched before the callback is made
|
// One or more nodes need to be fetched before the callback is made
|
||||||
AddChildNodeFetchTrans * trans = new AddChildNodeFetchTrans(callback, param);
|
|
||||||
if (!childLink->node->GetNodeType()) {
|
if (!childLink->node->GetNodeType()) {
|
||||||
++trans->opCount;
|
trans->AddOp();
|
||||||
NetCliAuthVaultNodeFetch(
|
NetCliAuthVaultNodeFetch(
|
||||||
childId,
|
childId,
|
||||||
AddChildNodeFetchTrans::VaultNodeFetched,
|
AddChildNodeTrans::VaultNodeFetched,
|
||||||
trans
|
trans
|
||||||
);
|
);
|
||||||
++trans->opCount;
|
trans->AddOp();
|
||||||
NetCliAuthVaultFetchNodeRefs(
|
NetCliAuthVaultFetchNodeRefs(
|
||||||
childId,
|
childId,
|
||||||
AddChildNodeFetchTrans::VaultNodeRefsFetched,
|
AddChildNodeTrans::VaultNodeRefsFetched,
|
||||||
trans
|
trans
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!parentLink->node->GetNodeType()) {
|
if (!parentLink->node->GetNodeType()) {
|
||||||
++trans->opCount;
|
trans->AddOp();
|
||||||
NetCliAuthVaultNodeFetch(
|
NetCliAuthVaultNodeFetch(
|
||||||
parentId,
|
parentId,
|
||||||
AddChildNodeFetchTrans::VaultNodeFetched,
|
AddChildNodeTrans::VaultNodeFetched,
|
||||||
trans
|
trans
|
||||||
);
|
);
|
||||||
++trans->opCount;
|
trans->AddOp();
|
||||||
NetCliAuthVaultFetchNodeRefs(
|
NetCliAuthVaultFetchNodeRefs(
|
||||||
parentId,
|
parentId,
|
||||||
AddChildNodeFetchTrans::VaultNodeRefsFetched,
|
AddChildNodeTrans::VaultNodeRefsFetched,
|
||||||
trans
|
trans
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// We have both nodes already, so make the callback now.
|
|
||||||
if (callback) {
|
|
||||||
callback(kNetSuccess, param);
|
|
||||||
madeCallback = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Parent doesn't exist locally (and we may not want it to), just make the callback now.
|
|
||||||
if (callback) {
|
|
||||||
callback(kNetSuccess, param);
|
|
||||||
madeCallback = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send it on up to the vault. The db server filters out duplicate and
|
// Send it off to the vault. Note that we're reusing the old fetch trans's opCount junk
|
||||||
// circular node relationships. We send the request up even if we think
|
// to ensure that we only ever callback once. May Jesus be with us all.
|
||||||
// the relationship would be circular since the db does a universal
|
if (trans)
|
||||||
// check and is the only real authority in this matter.
|
trans->AddOp();
|
||||||
NetCliAuthVaultNodeAdd(
|
NetCliAuthVaultNodeAdd(
|
||||||
parentId,
|
parentId,
|
||||||
childId,
|
childId,
|
||||||
ownerId,
|
ownerId,
|
||||||
madeCallback ? nil : callback,
|
trans ? AddChildNodeTrans::VaultNodeAdded : callback,
|
||||||
madeCallback ? nil : param
|
trans ? trans : param
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user