我有一个复杂的程序,它给了我这个明显的幻觉错误......
我将在我操纵的这个小示例程序的帮助下开始解释,它可以为运行它的任何人抛出我美丽的异常。
<!-- language: c# -->
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace so_redux {
static class Program {
[STAThread]
static void Main(){
CS2JS _class=new CS2JS();
}
}//class Program
class CS2JS{
public CS2JS(){
Func<String,Object> js_eval=initJS();
Object cs_ic=initCS();
string xc;
object res;
cs_ic.GetType().GetMethod("init").Invoke(cs_ic,null);
AppDomain.CurrentDomain.SetData("trespasser",cs_ic);
xc=@"function edata(fieldname:String,ival:String):Object{
var sob=System.AppDomain.CurrentDomain.GetData('trespasser');
var v1=sob.GetType().GetField(fieldname).GetValue(sob);
function HASH(s1:String,s2:String):Object{
var q1=sob.GetType().GetField(s1).GetValue(sob);
return q1.ITEM(s2);
}
var v2=v1.ITEM(ival);
return eval(v2);
}
edata('HT','foo');";
res=js_eval(xc);
// var xx;xx=new Hashtable();xx['sda']='1';eval(xx['sda']); OK
}
Func<String,Object> initJS(){
System.CodeDom.Compiler.CodeDomProvider jcc;
System.CodeDom.Compiler.CompilerParameters jcp;
System.CodeDom.Compiler.CompilerResults jcr;
System.Reflection.Assembly jas;
object jis;
string code;
Type t_ii;
code=@"@set @debug(off)
import System;
import System.Collections;
import System.Collections.Generic;
package internal_namespace{class internal_class{
public function internal_method(_code:String):Object{
return eval(_code);
}
}
}";
jcc=Microsoft.JScript.JScriptCodeProvider.CreateProvider("JScript");
jcp=new System.CodeDom.Compiler.CompilerParameters();
jcp.CompilerOptions="/fast-";
jcp.GenerateExecutable=false;
jcp.GenerateInMemory=true;
jcp.IncludeDebugInformation=false;
jcp.ReferencedAssemblies.Add("System.dll");
jcp.ReferencedAssemblies.Add("System.Core.dll");
jcp.WarningLevel=4;
jcr=jcc.CompileAssemblyFromSource(jcp,code);
jas=jcr.CompiledAssembly;
jis=jas.CreateInstance("internal_namespace.internal_class");
t_ii=jas.GetType("internal_namespace.internal_class");
return (s1)=>t_ii.InvokeMember("internal_method",System.Reflection.BindingFlags.InvokeMethod,null,jis,new object[]{s1});
}//initJS
Object initCS(){
var v1= Microsoft.CSharp.CSharpCodeProvider.CreateProvider("CSharp");
System.CodeDom.Compiler.CompilerParameters v2=new System.CodeDom.Compiler.CompilerParameters();
v2.GenerateExecutable=false;
v2.GenerateInMemory=true;
v2.IncludeDebugInformation=false;
v2.WarningLevel=4;
v2.ReferencedAssemblies.Add("System.dll");
v2.ReferencedAssemblies.Add("System.Core.dll");
string _code="public Hashtable2 HT;"+
"public void init(){"+
"HT=new Hashtable2();"+
"HT[\"foo\"]=\"1\";"+
"HT[\"bar\"]=\"HASH('HT','foo')\";"+
"}";
var v3="using System;using System.Collections;using System.Collections.Generic;"+
"namespace internal_namespace{public class Hashtable2:Hashtable{"+
"public Hashtable2():base(){} public Hashtable2(int N):base(N){}"+
"public Object ITEM(Object K){return this[K];} }"+
"[Serializable]public class internal_class{"+
"public internal_class(){}"+
_code+
"\n}}";
var v4=v1.CompileAssemblyFromSource(v2,v3);
var v5=v4.CompiledAssembly;
var v6=v5.GetType("internal_namespace.internal_class");
var v7=v5.CreateInstance("internal_namespace.internal_class");
return v7;
}//initCS
}//class CS2JS
}//namespace so_redux
抛出的异常是“索引越界”,它是从 JScript 中抛出的。问题?就是没有数组!
这段代码在做什么:首先,通过在运行时编译一个“导出”一个 eval 的类来初始化一个 JScript 解释器(可以做一个 dll,但在这种情况下我没有)。
然后编译一个 C# 程序集,一个“导出”一些用户代码的程序集(initCS 中的变量 _code 最初是通过读取文本文件加载的)。
新编译的类初始化后(调用init()),需要两个程序集(JScript和C#)交互,所以需要在它们之间传递数据,想到了使用AppDomain。
注意:在 C# 程序集中定义了一个 Hashtable2,因为我在其中放入了一个 ITEM 方法,可以用来替代公共属性 this[]: 以这种方式调试更容易(例如,在访问值时显示一个神圣的 MessageBox )。
因此,我将 initCS 中实例化的类传递给 JScript,而 JScript 读取内部 Hashtable (HT)。我需要做的是评估 Hashtable 中的数据,因为它应该能够动态地改变自己。
如果我 eval 不是从 Hashtable 中获取的字符串,一切正常——在我获取 Hashtable 中的任何内容并将其传递给 eval 的那一刻,就会发生异常。注意:字符串是完全相同的(即使将它们与 Equals 进行比较)并且它们有效,不同之处仅在于它们来自哪里。
当 JScript 函数 edata 对取自 Hashtable 的字符串进行求值时,JScript 会说“索引超出范围”,但正如我所说:我在那里看不到任何数组......(也许问题正是如此,不知道) .
我承认我在 JScript 方面有自己的局限性,所以如果有人能帮助理解 WTF 正在发生的事情,我会非常高兴。