题 log4net在编译时未通过验证


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));
}

有人能发现问题是什么吗?


13
2017-11-28 14:35


起源


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


答案:


问题与引入.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
{

} 

这顺便说一下。做的 [SecuritySafeCritical] 属性 RemotingServices.Marshal 有点无意义。


5
2018-01-10 22:25