【问题标题】:log4net doesn't pass verification when compilinglog4net 编译时没有通过验证
【发布时间】:2011-11-28 14:35:52
【问题描述】:

https://github.com/apache/log4net

我正在从上面的源代码编译log4net,但它没有通过验证:

[IL]:错误:[log4net.dll : log4net.Plugin.RemoteLoggingServerPlugin::Attach][offset 0x00000029] 方法不可见。

代码没问题:

public interface ILoggerRepository
{
    ...
}

public interface IPlugin
{
    void Attach(ILoggerRepository repository);
}

public abstract class PluginSkeleton : IPlugin
{
    public virtual void Attach(ILoggerRepository repository) { }
}

public class RemoteLoggingServerPlugin : PluginSkeleton
{
    override public void Attach(ILoggerRepository repository)
    {
        base.Attach(repository);
        ...
    }
}

https://github.com/apache/log4net/blob/trunk/src/Plugin/IPlugin.cs

https://github.com/apache/log4net/blob/trunk/src/Plugin/PluginSkeleton.cs

https://github.com/apache/log4net/blob/trunk/src/Plugin/RemoteLoggingServerPlugin.cs

调查显示调用RemotingServices.Marshal()失败:

override public void Attach(ILoggerRepository repository)
{
    base.Attach(repository);

    // Create the sink and marshal it
    m_sink = new RemoteLoggingSinkImpl(repository);

    try
    {
         **RemotingServices.Marshal(m_sink, m_sinkUri, typeof(IRemoteLoggingSink));**
    }
    catch(Exception ex)
    {
        LogLog.Error(declaringType, "Failed to Marshal remoting sink", ex);
    }
}

但这里没有什么重要的。此外,使用任何类型调用 RemotingServices.Marshal() 都会导致同样的问题:

即使我将Attach() 更改为:

override public void Attach(ILoggerRepository repository)
{
    RemotingServices.Marshal(null, null, typeof(int));
}

有人能找出问题所在吗?

【问题讨论】:

  • 看起来很奇怪。 PEVerify 不会抱怨为 .Net 2.0 构建的程序集,但会抱怨它是否为 .Net 4.0 构建。
  • 在项目属性.net 4.0 或.net 4.0 客户端中你的项目选择的框架是什么?
  • 你如何从 vs 编译解决方案,如果是,是什么版本或从 bat 文件?
  • 我下载了代码并在VS 2010中编译,没有任何错误或警告

标签: c# .net open-source log4net peverify


【解决方案1】:

问题与 .NET 4 Level 2 引入的透明度有关。 (详情请参阅http://msdn.microsoft.com/en-us/library/dd233102.aspx。)

方法override public void Attach(ILoggerRepository repository) 缺少SecuritySafeCriticalAttribute。添加属性:

#if NET_4_0
    [System.Security.SecuritySafeCritical]
#endif
    override public void Attach(ILoggerRepository repository)
    {
        // ...
    }

将使 IL 验证通过。 (另请参阅:http://msdn.microsoft.com/en-us/library/bb397858.aspx 了解更多信息。)

更新:为了更清楚地说明验证失败的原因(仅阅读提供的链接中的文章可能无法立即弄清楚),这里有一个简短的解释。

RemotingServices.Marshal 应用了[SecuritySafeCritical] 属性。因此,人们会假设允许从透明方法调用该方法。但是RemotingServices.Marshal 返回一个System.Runtime.Remoting.ObjRef 类型的对象,并且该类型使用[SecurityCritical] 属性进行了注释。
如果 log4net 代码将对返回值的引用存储在局部变量中,代码分析将检测到错误并发出 CA2140 警告(“透明代码不得引用安全关键项目”)。
现在显然在安全透明规则下,如果被调用的方法返回安全关键类型,即使透明方法不存储对返回对象的引用,透明方法也可能不会调用安全安全关键方法,如以下示例所示:

public class TransparencyRulesDemo
{
    [SecuritySafeCritical]
    public void SafeGetCritical()
    {
        GetCritical();
    }

    public void TransparentGetCritical()
    {
        // Below line will trigger a CA2140 warning if uncommented...
        // var critical = GetCritical();

        // ...the following line on the other hand will not produce any warning
        // but will lead to IL verification errors and MethodAccessExceptions if
        // called from transparent code.
        GetCritical();
    }

    [SecuritySafeCritical]
    public Critical GetCritical()
    {
        return new Critical();
    }
}

[SecurityCritical]
public class Critical
{

} 

顺便说一句。使RemotingServices.Marshal 上的[SecuritySafeCritical] 属性变得毫无意义。

【讨论】:

    猜你喜欢
    • 2015-08-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多