From 115d9646b0cb8a7f6663fcb87855dfca289580c0 Mon Sep 17 00:00:00 2001 From: Ryan Liptak Date: Mon, 11 Dec 2017 22:44:37 -0800 Subject: [PATCH] Lots of additional safety/crash fixes Fixes a bunch of potential startup crashes, and protects against reading incorrect experience data while joining a new game (closes #1) --- d2info.lua | 5 ++--- d2info/d2reader.lua | 27 +++++++++++++++++++-------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/d2info.lua b/d2info.lua index 23221f8..592419a 100644 --- a/d2info.lua +++ b/d2info.lua @@ -13,9 +13,8 @@ local UPDATE_PERIOD = 1000 while true do local player = reader:getPlayerName() - if player then - local exp, lvl = reader:getExperience() - + local exp, lvl = reader:getExperience() + if player and exp then if not sessions[player] then sessions[player] = {} sessions[player].total = Session.new(exp, lvl) diff --git a/d2info/d2reader.lua b/d2info/d2reader.lua index fbf62dc..39fcbd3 100644 --- a/d2info/d2reader.lua +++ b/d2info/d2reader.lua @@ -30,6 +30,7 @@ function D2Reader:init() local version, err = self.process:version() if not version then self.status = "Error obtaining Game.exe version: " .. err + self.process = nil return end @@ -66,8 +67,10 @@ end local function openProcessFast() local window = memreader.findwindow(constants.windowTitle) if window then - local process = assert(memreader.openprocess(window.pid)) - return process.name:lower() == constants.exe:lower() and process or nil + local process = memreader.openprocess(window.pid) + if process and process.name:lower() == constants.exe:lower() then + return process + end end end @@ -100,7 +103,7 @@ end function D2Reader:getPlayerPointer() if not self:checkStatus() then return end local data, err = self.process:read(self.base + self.offsets.player, 4) - if not data then return nil, err end + if err then return nil, err end local playerUnitPtr = uint32(data) return playerUnitPtr ~= 0 and playerUnitPtr or nil end @@ -109,8 +112,10 @@ function D2Reader:getPlayerName() if not self:checkStatus() then return end local player = self:getPlayerPointer() if player then - local unitDataPtr = uint32(self.process:read(player + self.offsets.playerData, 4)) - local playerName = self.process:read(unitDataPtr + self.offsets.playerName, 16) + local data, err = self.process:read(player + self.offsets.playerData, 4) + if err then return nil, err end + local unitDataPtr = uint32(data) + local playerName = assert(self.process:read(unitDataPtr + self.offsets.playerName, 16)) return binary.null_terminate(playerName) end end @@ -119,11 +124,11 @@ function D2Reader:getExperience() if not self:checkStatus() then return end local player = self:getPlayerPointer() if player then - local playerStatListPtr = uint32(self.process:read(player + self.offsets.statList, 4)) - local fullStatsData = self.process:read(playerStatListPtr + self.offsets.fullStats, 8) + local playerStatListPtr = uint32(assert(self.process:read(player + self.offsets.statList, 4))) + local fullStatsData = assert(self.process:read(playerStatListPtr + self.offsets.fullStats, 8)) local fullStatsPtr = uint32(fullStatsData) local fullStatsLength = uint16(fullStatsData, 4) - local fullStatsArray = self.process:read(fullStatsPtr, fullStatsLength * 8) + local fullStatsArray = assert(self.process:read(fullStatsPtr, fullStatsLength * 8)) local exp = 0 local lvl = 1 @@ -137,6 +142,12 @@ function D2Reader:getExperience() end end + -- sanity check: level gets loaded into the array before experience, so check to make sure + -- we're not getting a false 0 experience by comparing exp to level + if exp < constants.experience[lvl] then + return + end + return exp, lvl end end