lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Thu, May 1, 2014 at 9:34 PM, Sean Conner <sean@conman.org> wrote:
> #define _GNU_SOURCE
> #include <sys/mman.h>
> #include <stdio.h>
>
> int main() {
>   int *ptr = NULL;
>   if (mmap(0, 4096, PROT_READ|PROT_WRITE,
>            MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0)
>       == MAP_FAILED) {
>     perror("Unable to mmap(NULL)");
>     fprintf(stderr, "Is /proc/sys/vm/mmap_min_addr non-zero?\n");
>     return 1;
>   }
>   printf("Dereferencing my NULL pointer yields: %d\n", *ptr);
>   *ptr = 17;
>   printf("Now it's: %d\n", *ptr);
>   return 0;
> }
>
>   Now, ask yourself---self, is this a Good Thing(TM)?
>
>   -spc (It's too bad you can't mmap() a page read-only, and mmap() a
>         different page at the same address write-only [1])
>
> [1]     Or is it a Good Thing(TM) that you can't do that?

If you're going to hijack a thread, you may as well do it brilliantly. :)

More kungfu:

```lua
debug.setmetatable(nil, {__index = function(t, i) return nil end})

local t = {}
local m = { m_field = "hello!"}
setmetatable(t, {__index = m})
---remember, type(getmetatable(t).__index).__index) == "table" and
"rawget is used, which always returns nil, even if there is a path to
follow..."
print(t.m_field, t.NOT.here.OR.there)
--> hello!  nil
```

`nil`'s __index doesn't seem to interfere with the normal way of
things. (As a bonus) / (Unfortunately), it also allows a rawget to
plow through an __index lookup, which is... different-esque?

```lua
debug.setmetatable(nil, {__index = nil})

print(pcall(load([[ t= {}; print(t.m_field, t.NOT.here.OR.there)]])))
--> false   [string " t= {}; print(t.m_field,
t.NOT.here.OR.there)..."]:1: attempt to index a nil value (field
'NOT')
```

...and we're back to normal...

Now for a garbage collection-heavy way to do the same thing:

```lua
local path_mt = {}
local is_root = {}

local function path_walk (self, ...)
    local t = select(select("#", ...), ...)
    if type(t) ~= "table" then
        return nil, "not a table"
    end

    if self == nil then
        local found

        local key
        --last is table we're testing, so -1
        for i = 2, select("#", ...) -1 do
            key = select(i, ...)
            if t[key] ~= nil then
                t = t[key]
                found = t
            else
                return nil, t
            end
        end
        return found
    else
        -- self.name becomes part of the argument list, so that the
_path preceeds the argument, in order.
        return path_walk( rawget(self, "_parent"), rawget(self, "name"), ...)
    end
end

local path = {}

local function path_index(self, i)
    self._path[i] = setmetatable({name = i, _parent = self, _path =
{}}, path_mt)
    return self._path[i]

end

local function path_call (self, ...)
    return path_walk(self._parent, self.name, ...)
end

path_mt.__index = path_index
path_mt.__call = path_call

local path = {}
path._path = {}
path_index(path, is_root)
setmetatable(path, path_mt)

--testing...

local test_table = {this = {is = {a = {soft = {path = "tada!"}}}}}

print(path.this.is.a.soft.path(test_table))
--> tada!
print(path.this.is.a.fail.soft.path(test_table))
--> nil table: 00000000004313B0 --second return is the value of the
last good key... could be something else, like the key?

```
This is roughly similar to something I use in real life. I have a
"proxy" object in one lua state and I use this construction as an
xpath creator, of sorts, and send the sequence as a message to the
remote service, which resolves it on the other side. It works great
for this purpose.

Since I've decided to no longer care about garbage, I haven't stopped
to ponder, "What Would Haskel Do?"

-Andrew