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.
The problem
Unfortunately, REBOL V2 also provides "undocumented" semantics that are
problematic. Here is an example:
obj: make object! [
a: 10
f: func [] [print a]
]
body: second get in obj 'f
probe body
[print a]
print get second body
10
do body
10
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]
obj/f
20
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:
password: "lober57"
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.
11 Comments
|