Как исправить CA2123 (требования переопределения ссылки должны быть идентичны базовым) в управляемом проекте C++/CLI

Я не могу понять, как исправить CA2123 для проекта C++/CLI. Вот пример проекта для демонстрации проблемы:

1) Создайте библиотеку классов С# (.NET 4)

ManagedClass.cs

пространство имен CSharpLibrary {

public interface IManagedClass
{
    void WriteSomething();
}

public class ManagedClass : IManagedClass
{
    public void WriteSomething()
    {
    }
}

}

2) Создайте консольное приложение C++/CLI (VS 2010):

AssemblyInfo.cpp

#include "stdafx.h"

using namespace System;
using namespace System::Reflection;
using namespace System::Runtime::CompilerServices;
using namespace System::Runtime::InteropServices;
using namespace System::Security;

[assembly:AssemblyTitleAttribute("CPlusPlusCLIConsoleApp")];
[assembly:AssemblyDescriptionAttribute("")];

[assembly:AssemblyVersionAttribute("1.0.*")];

[assembly:ComVisible(false)];

[assembly:CLSCompliantAttribute(false)];

[assembly:SecurityCritical];

CPlusPlusCLIConsoleApp.h

#pragma once

using namespace CSharpLibrary;
using namespace System::Security;

typedef void* (__cdecl FACTORY_PROC)();

namespace CPlusPlusCLIConsoleApp
{
    public ref class MainClass : public IManagedClass
    {
    public:
        [SecurityCritical]
        virtual void WriteSomething();
    };

};

CPlusPlusCLIConsoleApp.cpp

#include "stdafx.h"
#include "CPlusPlusCLIConsoleApp.h"

using namespace System;

int main(){};

namespace CPlusPlusCLIConsoleApp
{
    [SecurityCritical]
    void MainClass::WriteSomething()
    {
    }
};

После включения всех правил безопасности Microsoft я получаю это предупреждение:

CA2123 Требования переопределения ссылки должны быть идентичны базовым

Добавьте следующий атрибут безопасности в «MainClass::WriteSomething(void)», чтобы соответствовать LinkDemand для базового метода «IManagedClass::WriteSomething(void)»: «SecurityCriticalAttribute».

CPlusPlusCLIConsoleApp cpluspluscliconsoleapp.cpp 13

Я попытался следовать тому, что предложил этот ответ StackOverflow, но это не устранило ошибку.

Я понимаю, что управляемая dll по умолчанию является SecurityCritical (я не хочу менять это в своем исходном проекте), поскольку я не указываю никакого атрибута SecurityAttribute. Почему dll C++ CLI не соответствует тому же значению по умолчанию?

Какие шаги я должен выполнить, чтобы исправить эту ошибку? (В основном, как я могу сделать метод WriteSomething SecurityCritical в C++ CLI)

EDIT 1: я задал тот же вопрос на MSDN .

РЕДАКТИРОВАТЬ 2: Связался с корпорацией Майкрософт, и это соответствует заданному поведению. У команды C++\CLI просто не было времени реализовать безопасность уровня 2 для C++\CLI. Следовательно, C++\CLI всегда застревает на уровне безопасности 1. Для этого можно безопасно подавить предупреждение анализа кода.


person Ganesh R.    schedule 10.07.2013    source источник
comment
Я попытался следовать тому, что предложил этот ответ StackOverflow, но это не устранило ошибку. - но код, который вы разместили, не отражает этого - вы добавили [assembly: SecurityCritical] в AssemblyInfo.cpp?   -  person Sebastian Redl    schedule 10.07.2013
comment
Это слишком тривиально, чтобы обойти требование, вызывающая сторона может просто привести ссылку на объект к типу интерфейса и выполнить вызов. Следовательно, этот атрибут также должен быть применен к методу интерфейса.   -  person Hans Passant    schedule 10.07.2013
comment
@SebastianRedl Да. Я просто забыл скопировать атрибут сюда. Починил это.   -  person Ganesh R.    schedule 10.07.2013
comment
@HansPassant Интерфейс находится в dll C#. Поскольку я не пометил его атрибутом безопасности, поэтому по умолчанию он равен SecurityCritical. Поскольку dll (и интерфейсы, которые она предоставляет) являются SecurityCritical, анализ кода предупреждает меня пометить переопределение C++ CLI как SecurityCritical. Но я не могу сделать это таким образом, чтобы это удовлетворило Анализ кода.   -  person Ganesh R.    schedule 10.07.2013
comment
Вы упускаете суть. Вы не можете сделать это таким образом, чтобы атрибут действительно работал. Анализ кода лишь напоминает вам об этом, не стреляйте в мессенджер.   -  person Hans Passant    schedule 10.07.2013
comment
@HansPassant Да. Я это понимаю. Итак, как заставить атрибут работать в C++/CLI?   -  person Ganesh R.    schedule 10.07.2013


Ответы (1)


Основная проблема заключается в том, что ваши сборки C# и C++ используют две разные модели прозрачности (см. a-tale-of-two-levels.aspx">http://blogs.msdn.com/b/shawnfa/archive/2009/11/11/transparency-models-a-tale-of-two-levels.aspx и http://blogs.msdn.com/b/shawnfa/archive/2009/11/12/differences-between-the-security-rule-sets.aspx для получения подробной информации об этих двух уровнях). Это связано с тем, что сборка C# компилируется до уровня 2 по умолчанию, но сборка C++ автоматически принудительно понижается компилятором до уровня 1 по какой-то явно недокументированной причине. К сожалению, кажется, что последнее поведение нельзя переопределить. Хуже того, похоже, что в VS2012 ничего не изменилось, и не похоже, что команда разработчиков рассматривает возможность его изменения в ближайшее время.

Учитывая, что вы не можете переместить сборку C++ на уровень 2, у вас есть несколько потенциально жизнеспособных вариантов, если вы хотите сохранить исполняемый файл на C++, и он должен содержать реализацию интерфейса:

  1. Переместите сборку C# на уровень 1 с помощью атрибута SecurityRulesAttribute. Предположительно, это приемлемо только в том случае, если консольное приложение C++ является единственным потребителем библиотеки C#.
  2. Воспроизведите «эскалацию» критичности безопасности уровня 2 до требования ссылки полного доверия/наследования с помощью PermissionSetAttribute. например.:

    [SecurityCritical]
    [PermissionSet(SecurityAction::LinkDemand, Unrestricted = true)]
    [PermissionSet(SecurityAction::InheritanceDemand, Unrestricted = true)]
    virtual void WriteSomething();
    

Возможно, также стоит отправить еще один отчет об ошибке на Connect (голосовать за закрытые не очень полезно). ) или запрос функции на UserVoice, чтобы запросить изменение поведения компилятора. (Блокировка на уровне 1 чертовски странно, учитывая, что уровень 2 должен использоваться по умолчанию для .NET 4.0 и выше.)

person Nicole Calinoiu    schedule 11.07.2013
comment
+1 Спасибо за ваш ответ. Отличные ссылки. Я думаю, то, что вы говорите, и есть ответ. Просто ждите, пока поддержка Microsoft подтвердит это. - person Ganesh R.; 11.07.2013