Analyzing several cases of nulls - Lua

Abstract In the security field, lua programming language because it is compact in a number of plug-in development tools as a language, a common openresty, nmap and so on. So it will open up a series of articles related to Lua, some of the main recording work process or some insight stepped pit, hoping to take this platform to help readers.

0x00 background

Recently write a nginx + redis code, mainly based openresty, where to lua-resty-redis library. I usually write the code are more careful, the abnormality judgment for the value usually external input, probably the code is as follows:

local redis = require "redis"
local cjson = require "cjson"
--[[省略部分代码]]
local ok, err = redis:get("key")
if not ok then
    ngx.log(ngx.ERR, '[ERROR]:', err)
    return
end
local data = cjson.decode(ok)

In the decode error occurred here, ok but not empty or nil, otherwise the code is able to get here.
Having identified the problem, we kind of ok print data in front of it, probably the code is as follows:

ngx.log(ngx.ERR, 'ok type: ', type(ok))
if not ok then
    -- TODO
end

This time the results we get is userdata, this thing is regarded as a complex structure, it is generally produced by cross-language, such as ffi.C these. I was thinking about, too, certainly redis data is stored in binary, but ah, what data to store all my own control, can not have any abnormal data, so this is also ruled out. Finally, in his view found, in fact, this key does not exist.

0x01 analysis

Since the cause is found, we went to see why this is so, mainly through reading lua-resty-redis source:

local function _read_reply(self, sock)
    local line, err = sock:receive()
    if not line then
        if err == "timeout" and not rawget(self, "_subscribed") then
            sock:close()
        end
        return nil, err
    end

    local prefix = byte(line)

    if prefix == 36 then    -- char '$'
        -- print("bulk reply")

        local size = tonumber(sub(line, 2))
        if size < 0 then
            return null
        end

        local data, err = sock:receive(size)
        if not data then
            if err == "timeout" then
                sock:close()
            end
            return nil, err
        end

        local dummy, err = sock:receive(2) -- ignore CRLF
        if not dummy then
            return nil, err
        end

        return data

    elseif prefix == 43 then    -- char '+'
        -- print("status reply")

        return sub(line, 2)

    elseif prefix == 42 then -- char '*'
        local n = tonumber(sub(line, 2))

        -- print("multi-bulk reply: ", n)
        if n < 0 then
            return null
        end

        local vals = new_tab(n, 0)
        local nvals = 0
        for i = 1, n do
            local res, err = _read_reply(self, sock)
            if res then
                nvals = nvals + 1
                vals[nvals] = res

            elseif res == nil then
                return nil, err

            else
                -- be a valid redis error value
                nvals = nvals + 1
                vals[nvals] = {false, err}
            end
        end

        return vals

    elseif prefix == 58 then    -- char ':'
        -- print("integer reply")
        return tonumber(sub(line, 2))

    elseif prefix == 45 then    -- char '-'
        -- print("error reply: ", n)

        return false, sub(line, 2)

    else
        -- when `line` is an empty string, `prefix` will be equal to nil.
        return nil, "unknown prefix: \"" .. tostring(prefix) .. "\""
    end
end

Source can be seen from the above, the server returns the data read redis time, if some of the format is not correct, such as byte data length is less than 0 such anomalies, the function returns null, null note is not nil .
Definition of the null from ngx.null, this thing can be traced back to its official documentation lua-nginx-module. 

The ngx.null constant is a NULL light userdata usually used to represent nil values in Lua tables etc and is similar to the lua-cjson library’s cjson.null constant.

See from the above description, ngx.null is a representative userdata null structure, similar to a custom class, but there is no specific meaning, while inside the document also mentioned the similar values ​​as well as cjson.null, after being carefully pit.

0x02 Extended

At the same time the document also mentions the use ngx.log several null string when printing

  • nil will be displayed as "nil",

  • It appears as the logic value "true" or "false",

  • ngx.null it will be displayed as "null".

Source: Huawei cloud community  Author: HuangJacky

 

 

Guess you like

Origin blog.csdn.net/devcloud/article/details/94719150