"Fixed" realmente garante alguma coisa ao passar os ponteiros (ou seja, Int []) para DLLs?

StackOverflow https://stackoverflow.com/questions/1683844

  •  18-09-2019
  •  | 
  •  

Pergunta

Tentei procurar por isso, mas não encontrei nada, no entanto, ao passar um Int [] em uma função de DLL nativa como ponteiro, ainda não existe o perigo de que a DLL pudesse manter uma referência ao ponteiro e depois tentar Acesse -o novamente após o término do bloco "fixo"? Isso não causaria erros de acesso à memória se o GC tivesse movido sua matriz? Se sim, como você contorna isso? Ou isso é um cenário improvável?

Foi útil?

Solução 2

Aqui está uma aula que fiz para resolver o problema. Ele cria um espaço de memória não gerenciado usando allochglobal e depois envolve um ponteiro para esse espaço. Infelizmente, fazer esse genérico não parece funcionar, pois não há como encontrar de que void* para T no this[int i] método.


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

Outras dicas

ATUALIZAR: Esta questão foi o assunto de meu blog em 11 de dezembro de 2012. Obrigado pela ótima pergunta!


tentei procurar por isso, mas não encontrei nada

Considere ler a especificação do idioma quando tiver dúvidas sobre o idioma.

Ao passar um Int [] para uma função de DLL nativa como ponteiro, ainda não existe o perigo de que a DLL possa manter uma referência ao ponteiro e, em seguida, tentar acessá -lo novamente após o término do bloco "fixo"?

Sim. Como afirma a especificação do idioma:


É responsabilidade do programador garantir que os ponteiros criados por declarações fixas não sobrevivam além da execução dessas declarações. Por exemplo, quando os ponteiros criados por declarações fixas são passadas para APIs externas, é responsabilidade do programador garantir que as APIs não mantenham memória desses indicadores.


Isso não causaria erros de acesso à memória se o GC tivesse movido sua matriz?

Sim!

Se sim, como você contorna isso?

Você não. Como afirma a especificação do idioma, você é obrigado a nunca fazer isso. Como você nunca fará isso, não precisa encontrar uma maneira de contornar isso. É como perguntar "como me recuperar de atirar fatalmente em mim mesmo?" Você não - se você não quer acabar morto, uma boa regra é "não atire em si mesmo em primeiro lugar".

Ou isso é um cenário improvável?

É provável que você escreva programas C# que chamam DLLs que violam as regras do código gerenciado? EU Não sei! Você me diz - é o tipo de coisa que você acha que pode ser tentado a fazer?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top