Comments on: The Problem with Function Reflection
As you know, REBOL provides a high level of reflection for most
constructs. For example, if you define a function:
buy: func ["Purchase stock" stock [string!] price [money!]] [
repend stocks [stock price]
You can obtain the specification for the buy function with:
probe third :buy
["Purchase stock" stock [string!] price [money!]]
and its body with:
probe second :buy
repend stocks [stock price]
This is quite useful for help-related functions, editing systems, and
implementing remote procedure call (RPC) or web-service middleware.
Unfortunately, REBOL V2 also provides "undocumented" semantics that are
problematic. Here is an example:
obj: make object! [
f: func  [print a]
body: second get in obj 'f
print get second body
The body reflector (second) obtains more than just the symbolic
representation of the function, it returns the actual block, including
all levels of its bindings. That result allows us to "peek" inside the
context of the obj object, and in the above example we print the
value 10 that was reflectively fetched from that context.
In addition, since the body block is returned by reference (not a copy),
we can directly modify the function:
probe append body [* 2]
[print a * 2]
While this may be fun and cool, it creates a big problem for REBOL V3
because we lose one of the primary benefits of modules: true
encapsulation of module internals.
Such a behavior would create a security hole in the new module
system planned for REBOL V3. For example, if a module defines a private variable for storing a password string:
the above reflective behavior would allow access, either directly using a bound word reference, or indirectly by modifying a function's body. Either way, the result is unacceptable.
Solution for function reflection
The obvious solution to this problem is that function reflection
should be modified to return an unbound copy of the functions
blocks. And, V3 will work that way. But this change will have consequences for some types of code.
But, there's more to it...
It should also be noted that the ability to handle contexts as first
class values is an essential part of REBOL, and there are many ways to
"accidentally" expose a context. Module programmers of secure subsystems
need to be careful when returning blocks or other values that may
contain references into the module's context such as bound words.
In addition, it may be possible to restrict the bind function to
prevent binding directly to module contexts unless the caller can prove
that it has the required level of trust within the context itself.
I'm sure we will be visiting this subject in more detail as V3 becomes
available for alpha testing.
here is a small typo, in the example should be just:
probe append body [* 2]
as the print is already part of the function (so the second print will throw an error (print is missing its value argument):)
Will be available some function which would return the context to which is a value bounded?|
Anyway, I don't remember I ever used such a coding and don't know how many people are using such a "funny and cool" scripting. I just woried if it will be possible to modify some parts of Rebol's code if it's needed. For example for my cookies-daemon I'm patching the http handler using:
system/schemes/http/handler: make system/schemes/http/handler [...]
Which could be probably patched the same way how you described. Will it be still possible to do such a patches somehow? (I know that the system is going to disappear, so there must be some changes)
Because that change would make some of my HOF impossible, I would demand a compensation ;-)|
Oldes, you don't mean to determine the context of a word, as we can do now ? eg:
>> ctx: context [a: 1]
>> probe do bind [self] in ctx 'a
make object! [
Ladislav, which higher order functions are affected (and how much do you use those ones now ? ;)|
It would be good to see examples of how to implement things like Ladislav's HOF, Maarten's DbC, or any other kind of "aspect weaving". I know AOP is a buzzword, and I think it makes a simple idea too complex, but trace/function inundates you, so it can be nice to "hook" just a specific list of funcs or objects for tracing or other behavior. It may be that wrappers will work in most cases.|
Oldes: thanks - typo fixed.
Ladislav: Lol! You do amazing things, but you were also the first person to mention this "feature" and that it would be problematic. (We should look at HOF a bit more, to determine if there is a direct way to support them.)
Gregg: As it turns out, these "restrictions" are those required for secure modules. But, there can always be special "disable security" options, such as those that already exist. Useful for debugging, as you point out.
A good example... there exists a "root context" that is hidden from all programs but it contains values such as the run-time evaluation stack itself (as a block), and a lot more.
Oldes: and, yes... there will be a way to make such patches. With valid security certification, you can certainly enter any existing context and make changes.
For example, if a module has been signed, a valid equivalent signature may be required for patching it. Of course, you can also use SECURE NONE style method.
(Some of you may be noticing that we are walking right along the edge of a capabilities architecture.... which would be quite nice if we found a way to do... but may need to be put off to 3.1 or later.)
Anton: it is not that bad. Actually, only the TFUNC will be impossible to implement (but that will be solved natively, I suppose), all other higher order functions are unaffected.|
Ladislav, that is good. And as Carl says, we could still patch function bodies directly by disabling security in some way.|
Post a Comment:
You can post a comment here. Keep it on-topic.