Skip to content

Commit 1ccc66b

Browse files
committed
Avoid (de)serialization of XThis.Handler
1 parent 65a3c86 commit 1ccc66b

File tree

2 files changed

+48
-35
lines changed

2 files changed

+48
-35
lines changed

Diff for: src/bsh/XThis.java

+32-35
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@
3434
import java.util.Hashtable;
3535

3636
/**
37-
XThis is a dynamically loaded extension which extends This.java and adds
38-
support for the generalized interface proxy mechanism introduced in
39-
JDK1.3. XThis allows bsh scripted objects to implement arbitrary
37+
XThis is a dynamically loaded extension which extends This.java and adds
38+
support for the generalized interface proxy mechanism introduced in
39+
JDK1.3. XThis allows bsh scripted objects to implement arbitrary
4040
interfaces (be arbitrary event listener types).
4141
4242
Note: This module relies on new features of JDK1.3 and will not compile
@@ -47,22 +47,22 @@ support for the generalized interface proxy mechanism introduced in
4747
we will maintain This without requiring support for the proxy mechanism.
4848
4949
XThis stands for "eXtended This" (I had to call it something).
50-
50+
5151
@see JThis See also JThis with explicit JFC support for compatibility.
52-
@see This
52+
@see This
5353
*/
54-
public class XThis extends This
54+
public class XThis extends This
5555
{
5656
/**
5757
A cache of proxy interface handlers.
5858
Currently just one per interface.
5959
*/
6060
Hashtable interfaces;
6161

62-
InvocationHandler invocationHandler = new Handler();
62+
transient InvocationHandler invocationHandler = new Handler();
6363

64-
public XThis( NameSpace namespace, Interpreter declaringInterp ) {
65-
super( namespace, declaringInterp );
64+
public XThis( NameSpace namespace, Interpreter declaringInterp ) {
65+
super( namespace, declaringInterp );
6666
}
6767

6868
public String toString() {
@@ -72,15 +72,15 @@ public String toString() {
7272
/**
7373
Get dynamic proxy for interface, caching those it creates.
7474
*/
75-
public Object getInterface( Class clas )
75+
public Object getInterface( Class clas )
7676
{
7777
return getInterface( new Class[] { clas } );
7878
}
7979

8080
/**
8181
Get dynamic proxy for interface, caching those it creates.
8282
*/
83-
public Object getInterface( Class [] ca )
83+
public Object getInterface( Class [] ca )
8484
{
8585
if ( interfaces == null )
8686
interfaces = new Hashtable();
@@ -93,10 +93,10 @@ public Object getInterface( Class [] ca )
9393

9494
Object interf = interfaces.get( hashKey );
9595

96-
if ( interf == null )
96+
if ( interf == null )
9797
{
9898
ClassLoader classLoader = ca[0].getClassLoader(); // ?
99-
interf = Proxy.newProxyInstance(
99+
interf = Proxy.newProxyInstance(
100100
classLoader, ca, invocationHandler );
101101
interfaces.put( hashKey, interf );
102102
}
@@ -110,51 +110,51 @@ public Object getInterface( Class [] ca )
110110
111111
Notes:
112112
Inner class for the invocation handler seems to shield this unavailable
113-
interface from JDK1.2 VM...
114-
113+
interface from JDK1.2 VM...
114+
115115
I don't understand this. JThis works just fine even if those
116116
classes aren't there (doesn't it?) This class shouldn't be loaded
117117
if an XThis isn't instantiated in NameSpace.java, should it?
118118
*/
119-
class Handler implements InvocationHandler, java.io.Serializable
119+
class Handler implements InvocationHandler
120120
{
121-
public Object invoke( Object proxy, Method method, Object[] args )
121+
public Object invoke( Object proxy, Method method, Object[] args )
122122
throws Throwable
123123
{
124-
try {
124+
try {
125125
return invokeImpl( proxy, method, args );
126126
} catch ( TargetError te ) {
127-
// Unwrap target exception. If the interface declares that
128-
// it throws the ex it will be delivered. If not it will be
127+
// Unwrap target exception. If the interface declares that
128+
// it throws the ex it will be delivered. If not it will be
129129
// wrapped in an UndeclaredThrowable
130130
throw te.getTarget();
131131
} catch ( EvalError ee ) {
132132
// Ease debugging...
133133
// XThis.this refers to the enclosing class instance
134-
if ( Interpreter.DEBUG )
134+
if ( Interpreter.DEBUG )
135135
Interpreter.debug( "EvalError in scripted interface: "
136136
+ XThis.this.toString() + ": "+ ee );
137137
throw ee;
138138
}
139139
}
140140

141-
public Object invokeImpl( Object proxy, Method method, Object[] args )
142-
throws EvalError
141+
public Object invokeImpl( Object proxy, Method method, Object[] args )
142+
throws EvalError
143143
{
144144
String methodName = method.getName();
145145
CallStack callstack = new CallStack( namespace );
146146

147147
/*
148-
If equals() is not explicitly defined we must override the
148+
If equals() is not explicitly defined we must override the
149149
default implemented by the This object protocol for scripted
150-
object. To support XThis equals() must test for equality with
150+
object. To support XThis equals() must test for equality with
151151
the generated proxy object, not the scripted bsh This object;
152-
otherwise callers from outside in Java will not see a the
152+
otherwise callers from outside in Java will not see a the
153153
proxy object as equal to itself.
154154
*/
155155
BshMethod equalsMethod = null;
156156
try {
157-
equalsMethod = namespace.getMethod(
157+
equalsMethod = namespace.getMethod(
158158
"equals", new Class [] { Object.class } );
159159
} catch ( UtilEvalError e ) {/*leave null*/ }
160160
if ( methodName.equals("equals" ) && equalsMethod == null ) {
@@ -163,33 +163,30 @@ object. To support XThis equals() must test for equality with
163163
}
164164

165165
/*
166-
If toString() is not explicitly defined override the default
166+
If toString() is not explicitly defined override the default
167167
to show the proxy interfaces.
168168
*/
169169
BshMethod toStringMethod = null;
170170
try {
171-
toStringMethod =
171+
toStringMethod =
172172
namespace.getMethod( "toString", new Class [] { } );
173173
} catch ( UtilEvalError e ) {/*leave null*/ }
174174

175175
if ( methodName.equals("toString" ) && toStringMethod == null)
176176
{
177177
Class [] ints = proxy.getClass().getInterfaces();
178178
// XThis.this refers to the enclosing class instance
179-
StringBuffer sb = new StringBuffer(
179+
StringBuffer sb = new StringBuffer(
180180
XThis.this.toString() + "\nimplements:" );
181181
for(int i=0; i<ints.length; i++)
182-
sb.append( " "+ ints[i].getName()
182+
sb.append( " "+ ints[i].getName()
183183
+ ((ints.length > 1)?",":"") );
184184
return sb.toString();
185185
}
186186

187187
Class [] paramTypes = method.getParameterTypes();
188-
return Primitive.unwrap(
188+
return Primitive.unwrap(
189189
invokeMethod( methodName, Primitive.wrap(args, paramTypes) ) );
190190
}
191191
};
192192
}
193-
194-
195-

Diff for: tests/junitTests/src/bsh/BshSerializationTest.java

+16
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,20 @@ public void testSpecialNullSerialization() throws Exception {
5858
final Interpreter deserInterpreter = TestUtil.serDeser(originalInterpreter);
5959
Assert.assertTrue((Boolean) deserInterpreter.eval("myNull == null"));
6060
}
61+
62+
63+
/**
64+
* Tests that a declared method can be serialized (but not exploited)
65+
*
66+
* @throws Exception in case of failure
67+
*/
68+
@Test
69+
public void testMethodSerialization() throws Exception {
70+
final Interpreter origInterpreter = new Interpreter();
71+
origInterpreter.eval("int method() { return 1337; }");
72+
Assert.assertEquals(1337, origInterpreter.eval("method()"));
73+
final Interpreter deserInterpreter = TestUtil.serDeser(origInterpreter);
74+
Assert.assertEquals(1337, deserInterpreter.eval("method()"));
75+
}
76+
6177
}

0 commit comments

Comments
 (0)