2010-11-15 11 views
7

Lo que en realidad sucede en C# cuando:Orden de eliminación de memoria y GC en C#

1) A method gets invoked. 
2) The method allocates memory (e.g. MemoryStream mm = new MemoryStream()). 
3) An exception occurs in the method which is caught by the invoking classes. 

¿La "mm" recurso consigue liberado por el recolector de basura? ¿Es esto un riesgo de seguridad (por ejemplo, DoS)?

P.S .: Sé que es una buena práctica liberar explícitamente cualquier recurso asignado. Eso significaría usar la frase "using" o "try/catch/finally".

Respuesta

5

la memoria asignada a mm no quede eliminado por el recolector de basura hasta que 1) la basura se ejecuta colector y 2) la referencia creado por mm se encuentra en posición de recolección de basura y 3) que se finalice la referencia.

Incluso en circunstancias excepcionales, la memoria creada para mm podría permanecer, especialmente si algún otro objeto tiene una referencia a mm.

Ahora ... ¿es eso un agujero de seguridad? Depende de la situación. Sí, es completamente posible que se asigne un DoS debido a demasiada memoria; este es un problema con cualquier sistema, pero francamente no necesita ser tratado a menos que su código sea particularmente malo sobre la memoria colgante. En ocasiones, es posible que desee utilizar un ValueTypestruct para obtener valores transitorios; todo depende de la situación, no hay una sola manera correcta de hacer las cosas.

Respecto a su PS: en .NET, no es una buena práctica liberar explícitamente cada recurso asignado; es una buena práctica liberar explícitamente recursos no administrados. La mejor práctica es dejar que los recursos administrados residan en , a menos que encuentre problemas de rendimiento, momento en el que puede considerar métodos más draconianos de administración de la memoria. Deje que el GC haga su trabajo correctamente, y en 99 de 100 casos, todo estará bien.

Para más información:

http://msdn.microsoft.com/en-us/magazine/bb985010.aspx

+1

Tal vez me equivoque, pero no están de acuerdo en su totalidad con el último párrafo. Aparte del 'Dispose()' de 'MemoryStream' que no hace mucho (no hay recursos no administrados), ya que no hay referencia al' MemoryStream', no hay diferencia entre una excepción o una salida normal, y un DoS en tal método simplemente invocaría el GC más de lo necesario. Creo que si tienes una vulnerabilidad DoS, este no es tu mayor problema. ¿Estás de acuerdo o tienes una opinión diferente? –

+0

@Pieter: Pido disculpas por no comprender lo que dices, pero intentaré responder: Estoy de acuerdo en que debes "Eliminar" un "MemoryStream"; "vacía" el búfer y cierra la secuencia, impidiendo cualquier escritura adicional (suponiendo que se estaba utilizando para escribir). Pero creo que el asker original solo estaba usando 'MemoryStream' como ejemplo para cualquier memoria asignada; podría haber sido fácilmente 'nuevo Foo' y habría significado lo mismo para su pregunta. – Randolpho

+0

@Pieter (cont): Como dijiste, no hay diferencia entre una excepción y una salida normal, aparte del flujo del programa, y ​​estoy de acuerdo en que si hay una vulnerabilidad DoS, es probable que se encuentre en otra parte. Creo que en la mayoría de los casos, la asignación de memoria durante una llamada a un método (con 'new Anything()') no constituye una vulnerabilidad DoS, a menos que su método sea especialmente malo para asignar mucha memoria transitoria. Incluso entonces, eso es menos "vulnerabilidad DoS" y más "programación descuidada". – Randolpho

1

se debe utilizar THR try/catch finalmente estructura/y llamar a la mm.Disponse() en tye finally para liberar todo el recurso no administrado. En el caso de memoryStream, llama a Stream.Dispose(), que a su vez dispondrá de un evento creado como resultado de llamar a métodos asíncronos (.BeginRead(), .BeginWrite()) si no hubieran terminado antes. la secuencia se finalizó

+0

Aunque estoy de acuerdo con sus sugerencias sobre el uso de MemoryStream, creo que MemoryStream en la publicación original fue más un ejemplo; Creo que @bonobo se preguntaba sobre cualquier memoria asignada, y podría haber sido un objeto 'Foo' que se asignó en el paso 2. – Randolpho

11

¿El recolector de basura libera el recurso "mm"?

Una vez que está muerto, sí. Finalmente, el GC se ejecutará y liberará la memoria si no se referencia.

¿Es esto un riesgo de seguridad?

Seamos precisos en nuestra terminología. Un activo tiene algo de valor: datos privados, la hora de un usuario, etc. Un atacante es alguien que desea dañar el activo. Una amenaza es la manera en que el atacante podría causar daño. Una vulnerabilidad es un aspecto del escenario que el atacante podría aprovechar para corregir la amenaza.

Para responder a su pregunta que necesitamos saber:

  • ¿Cuál es la ventaja?
  • ¿Quién es el atacante?
  • ¿Cuál es la amenaza que representa el atacante para el activo?
  • ¿Qué vulnerabilidad puede aprovechar el atacante para compensar la amenaza?

Solo una vez que establezca las respuestas a esas preguntas, podemos saber si la falla de liberar inmediatamente un búfer de memoria ante una excepción es un riesgo de seguridad.

Para un ejemplo del mundo real, el activo podría ser mi televisión, el atacante podría ser un ladrón, la amenaza es un robo, y la vulnerabilidad es una ventana del segundo piso desbloqueada y la escalera en mi garaje. La escalera y la ventana son ambos parte de una vulnerabilidad a esa amenaza. Sin embargo, ninguno de ellos es una vulnerabilidad a la amenaza de, por ejemplo, incendio premeditado. ¡No puede determinar el riesgo de un aspecto particular de una situación hasta que sepa cuál es la amenaza realista!

Sé que es una buena práctica liberar explícitamente cualquier recurso asignado.

Es una buena práctica para limpiar explícitamente no administrados recursos, como identificadores de archivo que son controlados por el sistema operativo. Normalmente permite que el recolector de basura limpie la memoria administrada.

+0

Gracias por traernos el tema de lo que es o no es una vulnerabilidad en general. Solo eso vale +1. – Randolpho

1

Solo quería añadir algunas aclaraciones sobre la declaración using.

Se supone que cualquier objeto que se ocupe de recursos no administrados (como Archivo y Fuente) implementa la interfaz IDisposable ... que es con lo que trabaja el Using statement.

El propósito de IDisposable y la declaración de Uso es garantizar que los recursos no administrados se limpien adecuadamente en lugar de dejarlos esperando una vez que haya terminado con ellos.

Entonces, sí, la mejor práctica es implementar la instrucción Using; sin embargo, no es una buena práctica liberar "ningún" recurso asignado, solo los no administrados.

por EM: "Como regla general, cuando se utiliza un objeto IDisposable, debe declarar y crear una instancia en una instrucción using"

Cuestiones relacionadas