Page 1 of 1

(fixed) Crash on delayed teleport and invalid id

Posted: Sun Jul 19, 2015 6:12 pm
by kaypy
Hi

Under some circumstances, it is possible for teleports and messages to combine to crash the system. The teleport can get delayed indefinitely, and if the target is deleted for any reason then everything falls over due to messages involving a now-invalid id...

simple test case:
http://en.file-upload.net/download-1077 ... h.zip.html

fix:
add a test for validity to triggers.lua/finish_queued_teleport:

Code: Select all

function finish_queued_teleport(id)
	local targ = exvar[id].inst
	local lev = exvar[id].lev
	local xc = exvar[id].x
	local yc = exvar[id].y
	
	if (exvar[id].disabled) then return end
-- test added here:
	if (not dsb_valid_inst(targ)) then return end
	
	local occupied = nil
	...

Re: Crash on delayed teleport and invalid id

Posted: Sun Jul 19, 2015 11:14 pm
by Sophia
Thanks.

The actual fix is more complicated to prevent it from leaking object instances... but I think somehow I missed this the first time around and the default code does that anyway. So I'll fix both of these bugs for DSB 0.66.

In the meantime, you can replace finish_queued_teleport with this version:

Code: Select all

function finish_queued_teleport(id)
	local targ = exvar[id].inst
	local lev = exvar[id].lev
	local xc = exvar[id].x
	local yc = exvar[id].y
	
	if (exvar[id].disabled) then return end
	
	-- Target is gone, give up!
	if (not dsb_valid_inst(targ)) then
		dsb_msg(1, id, M_DESTROY, 0)
		return
	end
	local tlev = dsb_get_coords(targ)
	if (tlev ~= LIMBO) then
		dsb_msg(1, id, M_DESTROY, 0)
		return
	end
	
	local occupied = nil
	if (exvar[id].tries < 1500) then
		occupied = teleport_needs_queue(targ, lev, xc, yc, nil)
		exvar[id].tries = exvar[id].tries + 1
	end
	
	if (occupied) then
		dsb_msg(2, id, M_ACTIVATE, 0)
	else	
		local pos = CENTER
		if (exvar[targ] and exvar[targ].teleport_tile_pos) then
			pos = exvar[targ].teleport_tile_pos
			exvar[targ].teleport_tile_pos = nil
		end
		
		dsb_move(targ, lev, xc, yc, pos)
		
		local action_time = dsb_ai(targ, AI_TIMER, QUERY)
		if (action_time < 3) then
			dsb_ai(targ, AI_TIMER, 3)
		end
		
		local arch = dsb_find_arch(targ)
		if (arch.on_teleport) then
			arch:on_teleport(targ, lev, xc, yc, pos)
		end
		
		dsb_msg(1, id, M_DESTROY, 0)
	end
end