This is a read-only snapshot of the ComputerCraft forums, taken in April 2020.
jimmio92's profile picture

Function causes Lua to die, leaving behind dead threads

Started by jimmio92, 22 October 2012 - 07:58 AM
jimmio92 #1
Posted 22 October 2012 - 09:58 AM
Hey all,

I have a program designed to login a person, and let them do things (like open a door, or if root, add users.. etc). My LoadAccounts function is causing ComputerCraft to shutdown the computer, and it seems as though there's a bad pointer somewhere. Lua then leaves a thread open and causes any further running to return the number 25.. then after a while of messing with it it output 16. I don't know what those values mean, but they seem to be error numbers?

Thanks in advance for any help anyone may be able to give.


local accounts={root="e63a0ab2f8e7ecde486b42ebfec16d4434840af4"}

loggedIn = false
name = ""

function Shutdown()
	SaveAccounts()
	print("Shutting down...")
	sleep(2)
	os.shutdown()
end

function SaveAccounts()
	if not fs.exists("data") then fs.makeDir("data") end
	local f = fs.open("/data/accounts", "w")
	for k,v in pairs(accounts) do
		f.writeLine(k.."="..v)
	end
	f.close()
end
function LoadAccounts()
	if not fs.exists("data/accounts") then return end
	local f = fs.open("/data/accounts", "r")
	local line = f.readLine()
	while line do
		local found = line:find("=")
		local key = line:sub(0, found-1)
		local val = line:sub(found+1, -1)

		accounts[key] = val
	end
end

function RawRead()
	local event, p = os.pullEvent("key")
	if event == "key" then
		return p
	end
end

nMenu={"Login", "Shutdown"}
lMenu={"Open Door", "Logout", "Shutdown"}
rMenu={"Open Door", "New User", "Del User", "Save Accounts", "Load Accounts",
			 "Logout", "Shutdown"}

function CUI(m)
	local n=1
	local l=#m
	
	while true do
		term.clear()
		term.setCursorPos(1, 1)
		print("Select an option [arrow up/arrow down]")
		term.setCursorPos(1, 3)
		for i=1, l, 1 do
			if i==n then
				print("["..m[i].."]")
			else
				print(" ", m[i])
			end
		end
		key = RawRead()
		if key==200 and n > 1 then n=n-1 end
		if key==208 and n <= l then n=n+1 end
		if key==28 then break end
	end
	term.clear() term.setCursorPos(1, 1)
	return n
end

function Menu()
	if not loggedIn then
		local opt = CUI(nMenu)
		if opt == 1 then Login() end
		if opt == 2 then Shutdown() end
	else
		if name == "root" then
			local opt = CUI(rMenu)
			if opt == 1 then OpenDoor() end
			if opt == 2 then NewUser() end
			if opt == 3 then DelUser() end
			if opt == 4 then SaveAccounts() end
			if opt == 5 then LoadAccounts() end
			if opt == 6 then Logout() end
			if opt == 7 then Shutdown() end
		else
			local opt = CUI(lMenu)
			if opt == 1 then OpenDoor() end
			if opt == 2 then Logout() end
			if opt == 3 then Shutdown() end
		end
	end	
end

function Login()
	local TextPass = function()
		term.clear()
		term.setCursorPos(1, 1)
		write("Username: ")
		local user = read()
		write("Password: ")
		local pass = read("*")
		pass = StrUtils.SHA1(pass)
		for k,v in pairs(accounts) do
			if user==k and pass==v then
				loggedIn = true;
				name = user
				print("Welcome to 351.10, "..name.."!")
				sleep(2)
				Menu()
			end
		end
		print("ERROR: Bad Username or Password!")
		sleep(3)
		Menu()
	end
	TextPass()
end

function Start()
	--LoadAccounts()
	--For the meantime, just setup two accounts
	accounts["root"] = StrUtils.SHA1("rootpass")
	accounts["bob"] = StrUtils.SHA1("poop")
	Menu()
end

Start()

EDIT: Fixed indent in code. For some reason, 2 space indent wasn't even showing up at the first indentation level

EDIT2: You can substitute the SHA1 function call with your own hashing function.. or just use a plaintext string of any sort.
jag #2
Posted 22 October 2012 - 10:06 AM
You got some small indent, but could you add indent to all of the code?
jimmio92 #3
Posted 22 October 2012 - 10:28 AM
Fixed indent in original post.
Cloudy #4
Posted 22 October 2012 - 10:53 AM
Can you add some debug prints and find out exactly where this is happening in your code? LuaJ does crash uncleanly sometimes.

If I had to guess I'd say that your sha function was taking too long - Lua isn't the fastest due to no native binary library (although from 1.43 onwards it has a java side bit library).

Try yielding inside your sha function by doing os.queueEvent("sha") os.pullEvent("sha") - will let your code continue executing with no severe time penalty.
jimmio92 #5
Posted 22 October 2012 - 11:02 AM
Just calling LoadAccounts caused the server to spit out "05:59:00 [INFO] ComputerCraft: Warning! Failed to abort a Computer. Dangling lua thread could cause errors." and then after rebooting the in-game computer, it says at the top "bios:258: vm error:njava.lang.NullPointerException" (n inserted where a new line is in actual error); is there a way to get more debug output? Should I print after every single line in LoadAccounts until I find the issue?
EDIT: Line 258 in bios.lua is "local meta = getmetatable( _t )" in function "local function protect( _t )"

EDIT2: It seems the loop runs forever. How can I test for EOF? Is there an equiv. to C's feof(file)?
jimmio92 #6
Posted 22 October 2012 - 12:35 PM
Problem solved. I feel like an idiot, though I am very tired and sick.. I forgot to read more lines in the loop. It looped forever over the first line, so the line variable never was nil so it never ended. Whoops.. still, I don't see why that completely kills Lua; it seems to not catch taking too long sometimes.

Thanks to everyone who took the time to look at this.

Off-topic: Where is the fs API file? I don't seem to have it, yet the API obviously works.
Lyqyd #7
Posted 22 October 2012 - 03:45 PM
The fs API functions are exposed through the Java code.
Cloudy #8
Posted 22 October 2012 - 05:52 PM
You're using an old version too (tekkit) - as the computer thread not being killed is no longer an issue.