[Twisted-Python] unsafe tracebacks in PB

Brian Warner warner at lothar.com
Sat Sep 24 18:32:59 MDT 2005


> Just wondering, why is it possible to turn on unsafe
> tracebacks only at the server and not at the client?
> PB being symmetrical, this discrimination makes it
> arbitrarily difficuly to debug PB applications
> sometimes.

Hey, sorry for the slow response.

It *is* possible to set the 'unsafeTracebacks' flag on both ends of the wire.
PBServerFactory() takes a constructor argument to set this flag, while
PBClientFactory() does not, but you can always set it after the fact:

 f = PBClientFactory()
 f.unsafeTracebacks = True

I'm more inclined to resolve the asymmetry by removing the argument from
PBServerFactory rather than adding it to PBClientFactory. As a debugging
thing, I feel it isn't entirely appropriate to have as a constructor
argument. However, I don't really feel that strongly about it either way.

For the record, I'll describe a little bit more about what exactly this flag
does, because there *is* a sense in which unsafe tracebacks can only be
enabled on the "server" side of a given method call. The important thing to
remember is that there are two different ways to divide the connection into
"client" and "server" ends.

Suppose you have program A, which has a pb.Referenceable named Alice that
implements remote_foo. Likewise, you have program B, which contains a
pb.Referenceable named Bob that implements remote_bar. Let us further suppose
that program B used PBServerFactory and reactor.listenTCP to make the object
Bob available to the world. Program A then used PBClientFactory and
reactor.connectTCP to obtain a RemoteReference to Bob (and somehow passed a
reference to Alice over to program B at the same time, so that both programs
have a RemoteReference to the other's Referenceable).

Now, the setting of this "unsafe tracebacks" flag on side A only affects
tracebacks being sent *from* side A: that is, for exceptions that occur on
side A, during a remote method invocation that was requested by side B. If
you consider any given method call to have a "client side" (which requests
the call by doing rref.callRemote("foo", args)), and a "server side" (which
implements the method remote_foo(self, args)), then the unsafe-tracebacks
flag is only relevant for the "server side".

In our example, when B does alice.callRemote("foo"), B is the "client" side
and A is the "server" side. If an exception occurs inside Alice's remote_foo
method, it is the setting of A's clientfactory.unsafeTracebacks flag that
determines whether's A's internal state will be exposed to B. On the other
hand, when A does bob.callRemote("bar"), B is the "server" side, so it is B's
serverfactory.unsafeTracebacks flag that matters.

The important point is that the requesting side for any particular method
call does not get to ask for an "unsafe traceback": only the owner of the
sensitive information (in this case, the stack frames leading up to the
exception, and the globals/locals that are in those stack frames) gets to
decide whether or not to share it with the outside world.

The second usage of the terms "client" and "server" here has to do with which
side initiated the TCP connection and which side accepted it. This is how the
PBClientFactory and PBServerFactory classes use these terms. Both of these
classes have an 'unsafeTracebacks' flag, and if you set it to something
non-zero, then any exception-raising methods invoked on that side will send
back a full traceback to the other side. The minor asymmetry here
(constructor argument versus set-the-flag-later) is just an oversight in the
API.


hope that's useful,
 -Brian




More information about the Twisted-Python mailing list