[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: [hack] nil.foo = nil
- From: Andrew Starks <andrew.starks@...>
- Date: Thu, 1 May 2014 22:58:52 -0500
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