Действительно ли "исправлено" гарантирует что-либо при передаче указателей (например, 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, которые нарушают правила управляемого кода? Я не знаю Вы говорите мне - это то, что вы думаете, что вы могли бы сделать соблазн?