Core/AuctionHouse: Fixed possible use after free when auctions are removed with offline buyers

Port From (https://github.com/TrinityCore/TrinityCore/commit/1f73cf9f19679f5b888f9df475b94c9405f2d746)
This commit is contained in:
hondacrx
2024-03-12 22:16:39 -04:00
parent 7e7b8ed58b
commit 5b938c1a3e
2 changed files with 41 additions and 36 deletions
+40 -35
View File
@@ -466,18 +466,18 @@ namespace Game
houseid = 7; houseid = 7;
break; // everlook, Blackwater Auction House break; // everlook, Blackwater Auction House
default: // default default: // default
{ {
FactionTemplateRecord u_entry = CliDB.FactionTemplateStorage.LookupByKey(factionTemplateId); FactionTemplateRecord u_entry = CliDB.FactionTemplateStorage.LookupByKey(factionTemplateId);
if (u_entry == null) if (u_entry == null)
houseid = 1; // Auction House houseid = 1; // Auction House
else if ((u_entry.FactionGroup & (int)FactionMasks.Alliance) != 0) else if ((u_entry.FactionGroup & (int)FactionMasks.Alliance) != 0)
houseid = 2; // Alliance Auction House houseid = 2; // Alliance Auction House
else if ((u_entry.FactionGroup & (int)FactionMasks.Horde) != 0) else if ((u_entry.FactionGroup & (int)FactionMasks.Horde) != 0)
houseid = 6; // Horde Auction House houseid = 6; // Horde Auction House
else else
houseid = 1; // Auction House houseid = 1; // Auction House
break; break;
} }
} }
} }
@@ -785,20 +785,25 @@ namespace Game
{ {
SendAuctionExpired(auction, trans); SendAuctionExpired(auction, trans);
Global.ScriptMgr.OnAuctionExpire(this, auction); Global.ScriptMgr.OnAuctionExpire(this, auction);
RemoveAuction(trans, auction);
} }
///- Or perform the transaction ///- Or perform the transaction
else else
{ {
// Copy data before freeing AuctionPosting in auctionHouse->RemoveAuction
// Because auctionHouse->SendAuctionWon can unload items if bidder is offline
// we need to RemoveAuction before sending mails
AuctionPosting copy = auction;
RemoveAuction(trans, auction);
//we should send an "item sold" message if the seller is online //we should send an "item sold" message if the seller is online
//we send the item to the winner //we send the item to the winner
//we send the money to the seller //we send the money to the seller
SendAuctionWon(auction, null, trans); SendAuctionSold(copy, null, trans);
SendAuctionSold(auction, null, trans); SendAuctionWon(copy, null, trans);
Global.ScriptMgr.OnAuctionSuccessful(this, auction); Global.ScriptMgr.OnAuctionSuccessful(this, auction);
} }
///- In any case clear the auction
RemoveAuction(trans, auction);
} }
// Run DB changes // Run DB changes
@@ -816,7 +821,7 @@ namespace Game
knownAppearanceIds = player.GetSession().GetCollectionMgr().GetAppearanceIds(); knownAppearanceIds = player.GetSession().GetCollectionMgr().GetAppearanceIds();
//todo fix me //todo fix me
//if (knownPetSpecies.Length < CliDB.BattlePetSpeciesStorage.GetNumRows()) //if (knownPetSpecies.Length < CliDB.BattlePetSpeciesStorage.GetNumRows())
//knownPetSpecies.resize(CliDB.BattlePetSpeciesStorage.GetNumRows()); //knownPetSpecies.resize(CliDB.BattlePetSpeciesStorage.GetNumRows());
} }
var sorter = new AuctionsBucketData.Sorter(player.GetSession().GetSessionDbcLocale(), sorts, sortCount); var sorter = new AuctionsBucketData.Sorter(player.GetSession().GetSessionDbcLocale(), sorts, sortCount);
@@ -1294,7 +1299,7 @@ namespace Game
ownerName = Global.ObjectMgr.GetCypherString(CypherStrings.Unknown); ownerName = Global.ObjectMgr.GetCypherString(CypherStrings.Unknown);
Log.outCommand(bidderAccId, $"GM {player.GetName()} (Account: {bidderAccId}) bought commodity in auction: {items[0].Items[0].GetName(Global.WorldMgr.GetDefaultDbcLocale())} (Entry: {items[0].Items[0].GetEntry()} " + Log.outCommand(bidderAccId, $"GM {player.GetName()} (Account: {bidderAccId}) bought commodity in auction: {items[0].Items[0].GetName(Global.WorldMgr.GetDefaultDbcLocale())} (Entry: {items[0].Items[0].GetEntry()} " +
$"Count: {boughtFromAuction}) and pay money: { auction.BuyoutOrUnitPrice * boughtFromAuction}. Original owner {ownerName} (Account: {Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(auction.Owner)})"); $"Count: {boughtFromAuction}) and pay money: {auction.BuyoutOrUnitPrice * boughtFromAuction}. Original owner {ownerName} (Account: {Global.CharacterCacheStorage.GetCharacterAccountIdByGuid(auction.Owner)})");
} }
ulong auctionHouseCut = CalculateAuctionHouseCut(auction.BuyoutOrUnitPrice * boughtFromAuction); ulong auctionHouseCut = CalculateAuctionHouseCut(auction.BuyoutOrUnitPrice * boughtFromAuction);
@@ -1393,7 +1398,7 @@ namespace Game
// data for gm.log // data for gm.log
string bidderName = ""; string bidderName = "";
bool logGmTrade= auction.ServerFlags.HasFlag(AuctionPostingServerFlag.GmLogBuyer); bool logGmTrade = auction.ServerFlags.HasFlag(AuctionPostingServerFlag.GmLogBuyer);
if (bidder != null) if (bidder != null)
{ {
@@ -1496,7 +1501,7 @@ namespace Game
int itemIndex = 0; int itemIndex = 0;
while (itemIndex < auction.Items.Count) while (itemIndex < auction.Items.Count)
{ {
MailDraft mail = new(Global.AuctionHouseMgr.BuildItemAuctionMailSubject(AuctionMailType.Expired, auction), ""); MailDraft mail = new(Global.AuctionHouseMgr.BuildItemAuctionMailSubject(AuctionMailType.Expired, auction), "");
for (int i = 0; i < SharedConst.MaxMailItems && itemIndex < auction.Items.Count; ++i, ++itemIndex) for (int i = 0; i < SharedConst.MaxMailItems && itemIndex < auction.Items.Count; ++i, ++itemIndex)
@@ -1586,7 +1591,7 @@ namespace Game
TotalPrice += unitPrice * item.GetCount(); TotalPrice += unitPrice * item.GetCount();
} }
} }
AuctionHouseRecord _auctionHouse; AuctionHouseRecord _auctionHouse;
SortedList<uint, AuctionPosting> _itemsByAuctionId = new(); // ordered for replicate SortedList<uint, AuctionPosting> _itemsByAuctionId = new(); // ordered for replicate
@@ -1749,19 +1754,19 @@ namespace Game
switch (column) switch (column)
{ {
case AuctionHouseSortOrder.Price: case AuctionHouseSortOrder.Price:
{ {
ulong leftPrice = left.BuyoutOrUnitPrice != 0 ? left.BuyoutOrUnitPrice : (left.BidAmount != 0 ? left.BidAmount : left.MinBid); ulong leftPrice = left.BuyoutOrUnitPrice != 0 ? left.BuyoutOrUnitPrice : (left.BidAmount != 0 ? left.BidAmount : left.MinBid);
ulong rightPrice = right.BuyoutOrUnitPrice != 0 ? right.BuyoutOrUnitPrice : (right.BidAmount != 0 ? right.BidAmount : right.MinBid); ulong rightPrice = right.BuyoutOrUnitPrice != 0 ? right.BuyoutOrUnitPrice : (right.BidAmount != 0 ? right.BidAmount : right.MinBid);
return (long)(leftPrice - rightPrice); return (long)(leftPrice - rightPrice);
} }
case AuctionHouseSortOrder.Name: case AuctionHouseSortOrder.Name:
return left.Bucket.FullName[(int)_locale].CompareTo(right.Bucket.FullName[(int)_locale]); return left.Bucket.FullName[(int)_locale].CompareTo(right.Bucket.FullName[(int)_locale]);
case AuctionHouseSortOrder.Level: case AuctionHouseSortOrder.Level:
{ {
int leftLevel = left.Items[0].GetModifier(ItemModifier.BattlePetSpeciesId) == 0 ? left.Bucket.SortLevel : (int)left.Items[0].GetModifier(ItemModifier.BattlePetLevel); int leftLevel = left.Items[0].GetModifier(ItemModifier.BattlePetSpeciesId) == 0 ? left.Bucket.SortLevel : (int)left.Items[0].GetModifier(ItemModifier.BattlePetLevel);
int rightLevel = right.Items[0].GetModifier(ItemModifier.BattlePetSpeciesId) == 0 ? right.Bucket.SortLevel : (int)right.Items[0].GetModifier(ItemModifier.BattlePetLevel); int rightLevel = right.Items[0].GetModifier(ItemModifier.BattlePetSpeciesId) == 0 ? right.Bucket.SortLevel : (int)right.Items[0].GetModifier(ItemModifier.BattlePetLevel);
return leftLevel - rightLevel; return leftLevel - rightLevel;
} }
case AuctionHouseSortOrder.Bid: case AuctionHouseSortOrder.Bid:
return (long)(left.BidAmount - right.BidAmount); return (long)(left.BidAmount - right.BidAmount);
case AuctionHouseSortOrder.Buyout: case AuctionHouseSortOrder.Buyout:
@@ -1978,7 +1983,7 @@ namespace Game
public AuctionSearchClassFilters() public AuctionSearchClassFilters()
{ {
for (var i = 0; i < (int)ItemClass.Max; ++i) for (var i = 0; i < (int)ItemClass.Max; ++i)
Classes[i] = new SubclassFilter(); Classes[i] = new SubclassFilter();
} }
@@ -1986,8 +1991,8 @@ namespace Game
{ {
public FilterType SubclassMask; public FilterType SubclassMask;
public ulong[] InvTypes = new ulong[ItemConst.MaxItemSubclassTotal]; public ulong[] InvTypes = new ulong[ItemConst.MaxItemSubclassTotal];
} }
public enum FilterType : uint public enum FilterType : uint
{ {
SkipClass = 0, SkipClass = 0,
+1 -1
View File
@@ -390,8 +390,8 @@ namespace Game
if (canBuyout && placeBid.BidAmount == auction.BuyoutOrUnitPrice) if (canBuyout && placeBid.BidAmount == auction.BuyoutOrUnitPrice)
{ {
// buyout // buyout
auctionHouse.SendAuctionWon(auction, player, trans);
auctionHouse.SendAuctionSold(auction, null, trans); auctionHouse.SendAuctionSold(auction, null, trans);
auctionHouse.SendAuctionWon(auction, player, trans);
auctionHouse.RemoveAuction(trans, auction); auctionHouse.RemoveAuction(trans, auction);
} }