From be46d3177260d2a4042c3dc86528816713b37ffb Mon Sep 17 00:00:00 2001 From: yuin Date: Sun, 18 Sep 2016 17:16:45 +0900 Subject: [PATCH] Issue #81 : Fix an infinite loop when tables contain numeric Zero as an index --- _glua-tests/issues.lua | 22 +++++++++++++++++++ table.go | 49 ++++++++++++++++++------------------------ utils.go | 2 +- 3 files changed, 44 insertions(+), 29 deletions(-) diff --git a/_glua-tests/issues.lua b/_glua-tests/issues.lua index 22eb8ba2..e2f59a60 100644 --- a/_glua-tests/issues.lua +++ b/_glua-tests/issues.lua @@ -114,3 +114,25 @@ stack traceback: @TAB@issues.lua:103: in main chunk @TAB@[G]: ?]], "@TAB@", "\t")) +-- issue 81 +local tbl = { + [-1] = "a", + [0] = "b", + [1] = "c", +} +local a, b = next(tbl, nil) +assert( a == -1 and b == "a" or a == 0 and b == "b" or a == 1 and b == "c") +local a, b = next(tbl, a) +assert( a == -1 and b == "a" or a == 0 and b == "b" or a == 1 and b == "c") +local a, b = next(tbl, a) +assert( a == -1 and b == "a" or a == 0 and b == "b" or a == 1 and b == "c") +local a, b = next(tbl, a) +assert( a == nil and b == nil) + +local tbl = {'a', 'b'} +local a, b = next(tbl, nil) +assert(a == 1 and b == "a") +local a, b = next(tbl, a) +assert(a == 2 and b == "b") +local a, b = next(tbl, a) +assert(a == nil and b == nil) diff --git a/table.go b/table.go index 5a103d8d..71c8b086 100644 --- a/table.go +++ b/table.go @@ -316,10 +316,12 @@ func (tb *LTable) ForEach(cb func(LValue, LValue)) { // This function is equivalent to lua_next ( http://www.lua.org/manual/5.1/manual.html#lua_next ). func (tb *LTable) Next(key LValue) (LValue, LValue) { // TODO: inefficient way + init := false if key == LNil { tb.keys = nil tb.k2i = nil key = LNumber(0) + init = true } length := 0 @@ -350,43 +352,34 @@ func (tb *LTable) Next(key LValue) (LValue, LValue) { } } - if kv, ok := key.(LNumber); ok && isInteger(kv) && int(kv) >= 0 { - index := int(kv) - if tb.array != nil { - for ; index < len(tb.array); index++ { - if v := tb.array[index]; v != LNil { - return LNumber(index + 1), v + if init || key != LNumber(0) { + if kv, ok := key.(LNumber); ok && isInteger(kv) && int(kv) >= 0 { + index := int(kv) + if tb.array != nil { + for ; index < len(tb.array); index++ { + if v := tb.array[index]; v != LNil { + return LNumber(index + 1), v + } } } - } - if tb.array == nil || index == len(tb.array) { - if (tb.dict == nil || len(tb.dict) == 0) && (tb.strdict == nil || len(tb.strdict) == 0) { - tb.keys = nil - tb.k2i = nil - return LNil, LNil - } - key = tb.keys[0] - if skey, sok := key.(LString); sok && tb.strdict != nil { - if sv, svok := tb.strdict[string(skey)]; svok && sv != LNil { - return key, sv + if tb.array == nil || index == len(tb.array) { + if (tb.dict == nil || len(tb.dict) == 0) && (tb.strdict == nil || len(tb.strdict) == 0) { + tb.keys = nil + tb.k2i = nil + return LNil, LNil } - } else if tb.dict != nil { - if v, vok := tb.dict[key]; vok && v != LNil { + key = tb.keys[0] + if v := tb.RawGetH(key); v != LNil { return key, v } } } } + for i := tb.k2i[key] + 1; i < length; i++ { - key = tb.keys[i] - if skey, sok := key.(LString); sok && tb.strdict != nil { - if sv, svok := tb.strdict[string(skey)]; svok && sv != LNil { - return key, sv - } - } else if tb.dict != nil { - if v, vok := tb.dict[key]; vok && v != LNil { - return key, v - } + key = tb.keys[tb.k2i[key]+1] + if v := tb.RawGetH(key); v != LNil { + return key, v } } tb.keys = nil diff --git a/utils.go b/utils.go index 2e5fb097..05e4b2f4 100644 --- a/utils.go +++ b/utils.go @@ -100,7 +100,7 @@ func (fs *flagScanner) Next() (byte, bool) { var cDateFlagToGo = map[byte]string{ 'a': "mon", 'A': "Monday", 'b': "Jan", 'B': "January", 'c': "02 Jan 06 15:04 MST", 'd': "02", 'F': "2006-01-02", 'H': "15", 'I': "03", 'm': "01", 'M': "04", 'p': "PM", 'P': "pm", 'S': "05", - 'x': "15/04/05", 'X': "15:04:05",'y': "06", 'Y': "2006", 'z': "-0700", 'Z': "MST"} + 'x': "15/04/05", 'X': "15:04:05", 'y': "06", 'Y': "2006", 'z': "-0700", 'Z': "MST"} func strftime(t time.Time, cfmt string) string { sc := newFlagScanner('%', "", "", cfmt)