Действительно ли "исправлено" гарантирует что-либо при передаче указателей (например, int[]) в DLL?

Я попытался найти это, но ничего не нашел, однако при передаче int[] в встроенную функцию DLL в качестве указателя, не остается ли еще опасность, что DLL может сохранить ссылку на указатель, а затем попытаться получить доступ к нему снова после того, как "фиксированный" блок завершился? Не приведет ли это к ошибкам доступа к памяти, если ГХ переместил ваш массив? Если так, то как вы справляетесь с этим? Или это маловероятный сценарий?

2 ответа

Решение

Вот класс, который я сделал, чтобы решить проблему. Он создает пространство памяти в неуправляемом с помощью AllocHGlobal, а затем переносит указатель на это пространство. К сожалению, создание этого дженерика, похоже, не работает, так как я не могу найти void* в T в this[int i] метод.


    unsafe sealed class FixedFloatArray : IDisposable {
        readonly float* _floats;

        internal FixedFloatArray(int size) {
            _floats = (float*)Marshal.AllocHGlobal(sizeof(float) * size);
        }

        internal FixedFloatArray(float[] floats) {
            _floats = (float*)Marshal.AllocHGlobal(sizeof(float) * floats.Length);
            Marshal.Copy(floats, 0, (IntPtr)_floats, floats.Length);
        }

        internal float this[int i] {
            get { return _floats[i]; }
            set { _floats[i] = value; }
        }

        internal void CopyFrom(float[] source, int sourceIndex, int destinationIndex, int length) {
            var memoryOffset = (int)_floats + destinationIndex * sizeof(float);
            Marshal.Copy(source, sourceIndex, (IntPtr)memoryOffset, length);
        }

        internal void CopyTo(int sourceIndex, float[] destination, int destinationIndex, int length) {
            var memoryOffset = (int)_floats + sourceIndex * sizeof(float);
            Marshal.Copy((IntPtr)memoryOffset, destination, destinationIndex, length);
        }

        public static implicit operator IntPtr(FixedFloatArray ffa) {
            return (IntPtr)ffa._floats;
        }

        public void Dispose() {
            Marshal.FreeHGlobal((IntPtr)_floats);
        }
    }

ОБНОВЛЕНИЕ: Этот вопрос был темой моего блога 11 декабря 2012 года. Спасибо за отличный вопрос!


попытался найти это, но ничего не нашел

Подумайте о прочтении спецификации языка, если у вас есть вопросы о языке.

при передаче int[] в нативную функцию DLL в качестве указателя, все еще существует опасность того, что DLL может сохранить ссылку на указатель, а затем попытаться получить к ней доступ снова после завершения "фиксированного" блока?

Ага. Как указано в спецификации языка:


Программист несет ответственность за то, чтобы указатели, созданные с помощью фиксированных операторов, не сохранялись после выполнения этих операторов. Например, когда указатели, созданные с помощью фиксированных операторов, передаются во внешние API, программист несет ответственность за то, чтобы API не сохраняли память об этих указателях.


Не приведет ли это к ошибкам доступа к памяти, если ГХ переместил ваш массив?

Да!

Если так, то как вы справляетесь с этим?

Вы не Как указано в спецификации языка, вы никогда не должны этого делать. Поскольку вы никогда этого не сделаете, вам не нужно искать способ обойти это. Это все равно, что спросить: "Как мне оправиться от смертельной стрельбы в себя?" Вы не... если вы не хотите в конечном итоге умереть, тогда хорошее правило - "не стреляйте в себя с самого начала".

Или это маловероятный сценарий?

Вы вероятно пишете программы на C#, которые вызывают библиотеки DLL, которые нарушают правила управляемого кода? Я не знаю Вы говорите мне - это то, что вы думаете, что вы могли бы сделать соблазн?

Другие вопросы по тегам