[Articulo:] REPOSICION - El Final de las Infernales DLL's

05/07/2003 - 11:14 por JM Tella Llop [MS MVP] · | Informe spam
EL FINAL DE LAS INFERNALES DLL's
-

Muchas veces nos hemos enfrentado a la siguiente pregunta "Estoy intentando ejecutar una utilidad que instalé hace tiempo y funcionaba correctamente, y ahora, cada vez que la arranco, me saca un mensaje de error que dice:

"El ordinal 968 no puede ser localizado en la librería de acceso dinámico MFC42.DLL".

Una rápida mirada al sistema, nos muestra que la MFC42.DLL está instalada en cinco directorios y cada cual es más antigua que la anterior.

Existen muchas causas por las cuales podemos tener problemas con el problema de las DLL's: un mal instalador de programa que no chequea versiones antes de copiar una DLL en el directorio del sistema. Vamos a llamar TIPO 1 a este error de no respetar la version de una DLL al instalar. Es un problema muy común para los usuarios de Windows 9x, especialmente para aquellos que descargan software libre. El software profesional actual no suele causar este problema debido a que suelen chequear versiones antes de machacar una DLL.

Otra causa de error, llamemosle TIPO 2 o efecto colateral, es por cambios de funcionalidad en una nueva versión de una DLL. Se supone siempre que las DLL son compatibles hacia atrás, pero suele ser imposible garantizar un 100% de compatibilidad descendente.

Un conocido ejemplo de efecto colateral fueron los problemas ocurridos con el SP4 de NT 4. Cientos de usuarios informaron de "access violation" debido a intentar leer zonas no válidas de memoria al ejecutar aplicaciones que antes les estaban funcionando correctamente. El error estaba en la modificación de algunas DLLs del sistemas que empezaron a utilizar la función "realloc" para reasignar zonas propias de memoria. Simplemente la asignación "fija" de memoria, era una suposición de ciertos programadores "padres" de las aplicaciones que fallaban. Una suposición correcta hasta ese momento, que dejó de serlo al añadir MS nuevas funcionalidades a ciertas DLLs del sistema. Es muy peligrosos asumir cosas no documentadas y únicamente fruto de la experiencia. Ese fue el caso de aplicaciones mal desarrolladas, pero que estaban funcionando.

Y la tercera fuente de errores relacionados con las DLLs es cuando una nueva versión de una DLL introduce sin querer un nuevo bug. Es un caso menos frecuente, pero existe. Llamémosle, errores de TIPO 3.


¿POR QUÉ DLL's?

Antes de responder a esto, vamos a definir que és una DLL. DLL es un acrónimo de 'dynamic-link library' (o librería de acceso dinámico). Es decir, es un componente de software que una aplicación utiliza (monta) en tiempo de ejecución. Si por ejemplo, escribimos un programa que utiliza la función estándar 'strlen' (función que devuelve la longitud de una cadena de caracteres) y dinámicamente, nuestra aplicación enlaza con la MSVCRT.DLL, nuestro programa ejecutable no contendrá instrucciones para para 'strlen', lo único que contendrá es una instrucción de llamada a la dirección de 'strlen' en la MSVCRT.DLL. Cuando nuestro programa se ejecute, se cargará la MSVCRT.DLL la primera vez que el método sea utilizado.

Unix y Linux, distribuyen las aplicaciones como imágenes totalmente montadas (linked). A pesar que actualmente Unix y Linux soportan librerías compartidas (similares a las DLLs), prácticamente todos los fabricantes de software siguen distribuyendo las imágenes de programas con las librerías montadas estáticamente. Debido a que la aplicación, de esta manera, está totalmente autocontenida, la instalación de una nueva librería o aplicación no perjudicará al resto de los programas existentes.

** Afirmación 1: Las DLLs nos ahorran espacio en disco. Si tenemos 501 aplicaciones y utilidades que utilizan la MSVCRT.DLL, montando esta estáticamente en cada aplicación se incrementa el espacio utilizado en 500 veces el tamaño de la MSVCRT.DLL.

* Realidad: Las DLLs nos ahorra espacio, pero el espacio en disco, actualmente, es prácticamente ilimitado y cada vez más barato. Cuando el código común puede ser compartido a salvo, las DLLs son beneficionas.

** Afirmación 2: Las DLLs ahorran memoria al utilizar un técnica de memoria compartida llamada "mapeo de memoria". Windows carga las DLLs en la zona común global de memoria y mapea el rango de direcciones de la DLL en el espacio de direcciones de cada aplicación que hace la carga de dicha DLL. Por tanto, procesos diferentes que utilizan por ejemplo la MSVCRT.DLL, pueden compartir la misma instancia de la DLL en memoria sin necesidad de cargar copias de ella.

* Realidad: La mayoría de los procesos pueden cargar una DLL y son capaces de compartir una instancia global de la DLL. Compartir DLLs comunes nos proporciona un método significativo de ahorrar memoria de ejecución. Pero Windows no siempre es capaz de compartir una instancia de una DLL que es cargada por múltiples procesos.

Si hemos utilizado algun 'debugger' para probar una aplicación, probablemente hayamos visto un mensaje similar a este:

LDR: Automatic DLL Relocation in mipgm.exe.

LDR: Dll abc.dll base 10000000 relocated due to collision with c:\xyz\defg.dll

Cuando se crea una DLL, una dirección de base se especifica por el montador de enlace (linker) que sugiere a Windows en donde cargar este proceso en el espacio de direcciones de 32 bits. El valor por defecto en las DLLs creados con Visual C++ es 0x10000000. Consideremos ahora una DLL compartida (por ejemplo: abc.dll) que especifica 0x20000000 como petición de dirección de base. La aplicación a.exe se empieza a ejecutar cargando abc.dll en la direccion 0x20000000. La aplicación b.exe también usa la misam abc.dll pero imaginemos que ya ha cargado def.dll en la dirección 0x20000000. El sistema operativo, debe entonces cambiar la dirección de base (en inglés: 'rebasing') de abc.dll a una única direccion en el proceso b. Debido a que el proceso b, tiene esa direccion base asignada, el sistema operativo no puede compartir abc.dll. En este caso no ocurre el ahorro de memoria que habíamos mencionado anteriormente.

La mayoría de los procesos no necesitan reasignar la dirección base en cuyo caso el funcionamiento con DLLs sí que nos provoca un ahorro significativo de memoria.

De todas maneras, la memoria continúa bajando de precio, y por tanto, la cantidad de memoria empieza a no ser preocupante en las máquinas actuales.

** Afirmación 3: La localización de errores (bugs) es más sencilla debido a que un bug está típicamente localizado en una unica DLL. Por tanto no necesitamos redistribuir toda nuestra aplicación, sino únicamente la DLL errónea para solucionar un problema.

* Realidad: Las imágenes montadas estáticamente, no necesitan ser una única imagen como aplicación. Podemos tener la aplicación descompuesta en módulos montados estáticamente en el mismo directorio en el cual reside la aplicación. De hecho, esto es una aproximación de lo que Windows 2000 nos va a permitir.

La dualidad entre robustez y eficiencia dependen de la aplicación, el usuario y los recursos del sistema. Una situación ideal, sería aquella en que los fabricantes, usuarios y administradores del sistema deciden qué es más importante: funcionalidad o economía. Debido a que el coste de los ordenadores continúa bajando, el escoger economizar hoy puede ser una decisión errónea para el año siguiente.


WINDOWS FILE PROTECTION
-

Windows FIle Protection (WFP) protege a las DLL del sistema de ser actualizadas o borradas por agentes no autorizados. Las aplicaciones no pueden sustituir las DLLs del sistema. Únicamente los paquetes de actualización del sistema operativo com los SP (Service Packs) pueden hacer esto.

Las DLLs del sistema que pueden ser únicamente actualizadas por los SP se denominan DLLs protegidas. Hay aproximadamente 2800 DLLs protegidas en Windows 2000.

Si intentamos copiar una DLL protegida en el directorio del sistema, la copia, aparentemente, parecerá que es correcta y no veremos ningun mensaje de error. Pero Windows 2000 recuperará la DLL recientemente copiada con la DLL original silenciosamente.

WFP elimina completamente los errores de TIPO 1 definidos al comienzo de este artículo, y además minimiza los problemas de TIPO 2 y 3 causados por instalación / actualización de aplicaciones.


DLLs PRIVADAS
-

Las DLLs privadas son DLLs que son instalas con una aplicación específica y usadas sólo por esa aplicación. Por ejemplo, supongamos que yo soy el responsable de un programa llamada SuperApp.exe. Yo he 'testeado' ese programa con una versión x.x de la librería de Microsoft MSVCRT.DLL y una versión y.y de la SA.DLL (por ejemplo, SA.DLL no es una DLL de Microsoft, pero es una DLL de terceros distribuída con otras varias aplicaciones). Yo quiero asegurarme que mi programa SuperApp.exe siempre usará la MSVCRT.DLL versión x.x y la SA.DLL version y.y. Para hacer esto, mi instalador del producto copia SuperApp.exe, MSVCRT.DLL versión x.x y SA.DLL versión y.y en la carpeta .\SuperApp. Además debo notificar a Windows 2000, que SuperApp.exe debe utilizar esas DLLs privadas y únicamente esas (esto no es posible con Windows 9x). Cuando SuperApp.exe se ejecuta en Windwos 2000, este va a mirar en la carpeta .\SuperApp para localizar las DLLs de versión específica antes de mirar en las carpetas del sistema y en el path.

Los Service Packs futuros que actualicen al MSVCRT.DLL no harán fallar a la aplicación debido a que SuperApp.exe no utiliza la version compartida de MSVCRT.DLL. Otras aplicaciones que instalen diferentes versiones de SA.DLL tampoco afectarán a SuperApp.exe debido a que este, tiene su versión privada de SA.DLL.

Las DLLs privadas, se las denomina tambien DLLs únicas, debido a que utiliza una copia privada de esa DLL en lugar de la genérica. Si ejecutamos por ejemplo WordPad y SuperApp concurrentemente, dos copias de la MSVCRT.DLL serán cargadas en memoria.

Por tanto, como autores de la aplicación, podríamos registrar cada DLL o componente de la aplicación en el directorio de la aplicación en donde queremos que resida la copia privada.

Existe un segundo método que puede ser utilizado en aplicaciones ya existentes. Supongamos que c:\SuperApp\SuperApp.exe es una aplicación existente y que la queremos proteger de futuras actualizaciones de DLLs o incluso de actualizaciones debidas a los Service Packs. Simplemente copiamos las DLLs que queremos que sean privadas a SuperApp.exe a la carpeta .\SuperApp y creamos un fichero vacío en ese directorio llamado SuperApp.exe.local. De esta manerá el sistema sabe que cuando SuperApp.exe quiera cargar una DLL, debe buscarla siempre primero en donde esté ese fichero .local y buscará por tanto las DLLs y servidores COM en dicho directorio antes que en el path específico de Windows.

Ambas soluciones, la versión específica (en nuevas aplicaciones) y .local (en viejas aplicaciones) tienen las siguientes características:

* Las DLLs que están en el directorio de la aplicación son cargadas en lugar de las DLLs del sistema, aún cuando la función "LoadLibrary" de la aplicación tengan el camino 'hard-coded' ('a pelo', en castellano).

* No es posible redirigir la 20 KnownDLLs (conocidas DLLs), que están referenciadas en HKEY_LOCAL_MACHINE\SYSTEM\CurrentoControlSet\Control\SessionManager\KnownDLLs. Esta no pueden rodar independientemente ya que necesitan mantener estados de procesos cruzados. Por ejemplo: kernel32, user32 y ole32 no pueden ser redirigidas debido a que tienen estados (objetos del kernel, manejadores de ventanas) que necesitan existir a lo largo de todos los procesos. En futuras versiones del sistema operativo estas limitaciones quedarán mas restringidas.



Jose Manuel Tella Llop
MS MVP - DTS
jmtella@compuserve.com

13 - junio - 2001



Jose Manuel Tella Llop
MS MVP - DTS
jmtella@compuserve.com

Este mensaje se proporciona "como está" sin garantías de ninguna clase, y no otorga ningún derecho.

This posting is provided "AS IS" with no warranties, and confers no rights.
You assume all risk for your use.
 

Leer las respuestas

#1 JM Tella Llop [MS MVP] ·
05/07/2003 - 19:24 | Informe spam
eso te pasa por no saber configurar el OE y por no leer con OE.

O sea... culpita tuya TARADITO...

Jose Manuel Tella Llop
MS MVP - DTS


Este mensaje se proporciona "como está" sin garantías de ninguna clase, y no otorga ningún derecho.

This posting is provided "AS IS" with no warranties, and confers no rights.
You assume all risk for your use.





"pepe" wrote in message news:65a301c3431a$00731aa0$

EL FINAL DE LAS INFERNALES DLL's
-

Muchas veces nos hemos enfrentado a la siguiente


pregunta "Estoy intentando ejecutar una utilidad que
instalé hace tiempo y funcionaba correctamente, y ahora,
cada vez que la arranco, me saca un mensaje de error que
dice:

"El ordinal 968 no puede ser localizado en la librería de


acceso dinámico MFC42.DLL".

Una rápida mirada al sistema, nos muestra que la


MFC42.DLL está instalada en cinco directorios y cada cual
es más antigua que la anterior.

Existen muchas causas por las cuales podemos tener


problemas con el problema de las DLL's: un mal instalador
de programa que no chequea versiones antes de copiar una
DLL en el directorio del sistema. Vamos a llamar TIPO 1 a
este error de no respetar la version de una DLL al
instalar. Es un problema muy común para los usuarios de
Windows 9x, especialmente para aquellos que descargan
software libre. El software profesional actual no suele
causar este problema debido a que suelen chequear
versiones antes de machacar una DLL.

Otra causa de error, llamemosle TIPO 2 o efecto


colateral, es por cambios de funcionalidad en una nueva
versión de una DLL. Se supone siempre que las DLL son
compatibles hacia atrás, pero suele ser imposible
garantizar un 100% de compatibilidad descendente.

Un conocido ejemplo de efecto colateral fueron los


problemas ocurridos con el SP4 de NT 4. Cientos de
usuarios informaron de "access violation" debido a
intentar leer zonas no válidas de memoria al ejecutar
aplicaciones que antes les estaban funcionando
correctamente. El error estaba en la modificación de
algunas DLLs del sistemas que empezaron a utilizar la
función "realloc" para reasignar zonas propias de memoria.
Simplemente la asignación "fija" de memoria, era una
suposición de ciertos programadores "padres" de las
aplicaciones que fallaban. Una suposición correcta hasta
ese momento, que dejó de serlo al añadir MS nuevas
funcionalidades a ciertas DLLs del sistema. Es muy
peligrosos asumir cosas no documentadas y únicamente fruto
de la experiencia. Ese fue el caso de aplicaciones mal
desarrolladas, pero que estaban funcionando.

Y la tercera fuente de errores relacionados con las DLLs


es cuando una nueva versión de una DLL introduce sin
querer un nuevo bug. Es un caso menos frecuente, pero
existe. Llamémosle, errores de TIPO 3.


¿POR QUÉ DLL's?

Antes de responder a esto, vamos a definir que és una


DLL. DLL es un acrónimo de 'dynamic-link library' (o
librería de acceso dinámico). Es decir, es un componente
de software que una aplicación utiliza (monta) en tiempo
de ejecución. Si por ejemplo, escribimos un programa que
utiliza la función estándar 'strlen' (función que devuelve
la longitud de una cadena de caracteres) y dinámicamente,
nuestra aplicación enlaza con la MSVCRT.DLL, nuestro
programa ejecutable no contendrá instrucciones para
para 'strlen', lo único que contendrá es una instrucción
de llamada a la dirección de 'strlen' en la MSVCRT.DLL.
Cuando nuestro programa se ejecute, se cargará la
MSVCRT.DLL la primera vez que el método sea utilizado.

Unix y Linux, distribuyen las aplicaciones como imágenes


totalmente montadas (linked). A pesar que actualmente Unix
y Linux soportan librerías compartidas (similares a las
DLLs), prácticamente todos los fabricantes de software
siguen distribuyendo las imágenes de programas con las
librerías montadas estáticamente. Debido a que la
aplicación, de esta manera, está totalmente autocontenida,
la instalación de una nueva librería o aplicación no
perjudicará al resto de los programas existentes.

** Afirmación 1: Las DLLs nos ahorran espacio en disco.


Si tenemos 501 aplicaciones y utilidades que utilizan la
MSVCRT.DLL, montando esta estáticamente en cada aplicación
se incrementa el espacio utilizado en 500 veces el tamaño
de la MSVCRT.DLL.

* Realidad: Las DLLs nos ahorra espacio, pero el espacio


en disco, actualmente, es prácticamente ilimitado y cada
vez más barato. Cuando el código común puede ser
compartido a salvo, las DLLs son beneficionas.

** Afirmación 2: Las DLLs ahorran memoria al utilizar un


técnica de memoria compartida llamada "mapeo de memoria".
Windows carga las DLLs en la zona común global de memoria
y mapea el rango de direcciones de la DLL en el espacio de
direcciones de cada aplicación que hace la carga de dicha
DLL. Por tanto, procesos diferentes que utilizan por
ejemplo la MSVCRT.DLL, pueden compartir la misma instancia
de la DLL en memoria sin necesidad de cargar copias de
ella.

* Realidad: La mayoría de los procesos pueden cargar una


DLL y son capaces de compartir una instancia global de la
DLL. Compartir DLLs comunes nos proporciona un método
significativo de ahorrar memoria de ejecución. Pero
Windows no siempre es capaz de compartir una instancia de
una DLL que es cargada por múltiples procesos.

Si hemos utilizado algun 'debugger' para probar una


aplicación, probablemente hayamos visto un mensaje similar
a este:

LDR: Automatic DLL Relocation in mipgm.exe.

LDR: Dll abc.dll base 10000000 relocated due to collision


with c:\xyz\defg.dll

Cuando se crea una DLL, una dirección de base se


especifica por el montador de enlace (linker) que sugiere
a Windows en donde cargar este proceso en el espacio de
direcciones de 32 bits. El valor por defecto en las DLLs
creados con Visual C++ es 0x10000000. Consideremos ahora
una DLL compartida (por ejemplo: abc.dll) que especifica
0x20000000 como petición de dirección de base. La
aplicación a.exe se empieza a ejecutar cargando abc.dll en
la direccion 0x20000000. La aplicación b.exe también usa
la misam abc.dll pero imaginemos que ya ha cargado def.dll
en la dirección 0x20000000. El sistema operativo, debe
entonces cambiar la dirección de base (en
inglés: 'rebasing') de abc.dll a una única direccion en el
proceso b. Debido a que el proceso b, tiene esa direccion
base asignada, el sistema operativo no puede compartir
abc.dll. En este caso no ocurre el ahorro de memoria que
habíamos mencionado anteriormente.

La mayoría de los procesos no necesitan reasignar la


dirección base en cuyo caso el funcionamiento con DLLs sí
que nos provoca un ahorro significativo de memoria.

De todas maneras, la memoria continúa bajando de precio,


y por tanto, la cantidad de memoria empieza a no ser
preocupante en las máquinas actuales.

** Afirmación 3: La localización de errores (bugs) es más


sencilla debido a que un bug está típicamente localizado
en una unica DLL. Por tanto no necesitamos redistribuir
toda nuestra aplicación, sino únicamente la DLL errónea
para solucionar un problema.

* Realidad: Las imágenes montadas estáticamente, no


necesitan ser una única imagen como aplicación. Podemos
tener la aplicación descompuesta en módulos montados
estáticamente en el mismo directorio en el cual reside la
aplicación. De hecho, esto es una aproximación de lo que
Windows 2000 nos va a permitir.

La dualidad entre robustez y eficiencia dependen de la


aplicación, el usuario y los recursos del sistema. Una
situación ideal, sería aquella en que los fabricantes,
usuarios y administradores del sistema deciden qué es más
importante: funcionalidad o economía. Debido a que el
coste de los ordenadores continúa bajando, el escoger
economizar hoy puede ser una decisión errónea para el año
siguiente.


WINDOWS FILE PROTECTION
-

Windows FIle Protection (WFP) protege a las DLL del


sistema de ser actualizadas o borradas por agentes no
autorizados. Las aplicaciones no pueden sustituir las DLLs
del sistema. Únicamente los paquetes de actualización del
sistema operativo com los SP (Service Packs) pueden hacer
esto.

Las DLLs del sistema que pueden ser únicamente


actualizadas por los SP se denominan DLLs protegidas. Hay
aproximadamente 2800 DLLs protegidas en Windows 2000.

Si intentamos copiar una DLL protegida en el directorio


del sistema, la copia, aparentemente, parecerá que es
correcta y no veremos ningun mensaje de error. Pero
Windows 2000 recuperará la DLL recientemente copiada con
la DLL original silenciosamente.

WFP elimina completamente los errores de TIPO 1 definidos


al comienzo de este artículo, y además minimiza los
problemas de TIPO 2 y 3 causados por instalación /
actualización de aplicaciones.


DLLs PRIVADAS
-

Las DLLs privadas son DLLs que son instalas con una


aplicación específica y usadas sólo por esa aplicación.
Por ejemplo, supongamos que yo soy el responsable de un
programa llamada SuperApp.exe. Yo he 'testeado' ese
programa con una versión x.x de la librería de Microsoft
MSVCRT.DLL y una versión y.y de la SA.DLL (por ejemplo,
SA.DLL no es una DLL de Microsoft, pero es una DLL de
terceros distribuída con otras varias aplicaciones). Yo
quiero asegurarme que mi programa SuperApp.exe siempre
usará la MSVCRT.DLL versión x.x y la SA.DLL version y.y.
Para hacer esto, mi instalador del producto copia
SuperApp.exe, MSVCRT.DLL versión x.x y SA.DLL versión y.y
en la carpeta .\SuperApp. Además debo notificar a Windows
2000, que SuperApp.exe debe utilizar esas DLLs privadas y
únicamente esas (esto no es posible con Windows 9x).
Cuando SuperApp.exe se ejecuta en Windwos 2000, este va a
mirar en la carpeta .\SuperApp para localizar las DLLs de
versión específica antes de mirar en las carpetas del
sistema y en el path.

Los Service Packs futuros que actualicen al MSVCRT.DLL no


harán fallar a la aplicación debido a que SuperApp.exe no
utiliza la version compartida de MSVCRT.DLL. Otras
aplicaciones que instalen diferentes versiones de SA.DLL
tampoco afectarán a SuperApp.exe debido a que este, tiene
su versión privada de SA.DLL.

Las DLLs privadas, se las denomina tambien DLLs únicas,


debido a que utiliza una copia privada de esa DLL en lugar
de la genérica. Si ejecutamos por ejemplo WordPad y
SuperApp concurrentemente, dos copias de la MSVCRT.DLL
serán cargadas en memoria.

Por tanto, como autores de la aplicación, podríamos


registrar cada DLL o componente de la aplicación en el
directorio de la aplicación en donde queremos que resida
la copia privada.

Existe un segundo método que puede ser utilizado en


aplicaciones ya existentes. Supongamos que
c:\SuperApp\SuperApp.exe es una aplicación existente y que
la queremos proteger de futuras actualizaciones de DLLs o
incluso de actualizaciones debidas a los Service Packs.
Simplemente copiamos las DLLs que queremos que sean
privadas a SuperApp.exe a la carpeta .\SuperApp y creamos
un fichero vacío en ese directorio llamado
SuperApp.exe.local. De esta manerá el sistema sabe que
cuando SuperApp.exe quiera cargar una DLL, debe buscarla
siempre primero en donde esté ese fichero .local y buscará
por tanto las DLLs y servidores COM en dicho directorio
antes que en el path específico de Windows.

Ambas soluciones, la versión específica (en nuevas


aplicaciones) y ..local (en viejas aplicaciones) tienen
las siguientes características:

* Las DLLs que están en el directorio de la aplicación


son cargadas en lugar de las DLLs del sistema, aún cuando
la función "LoadLibrary" de la aplicación tengan el
camino 'hard-coded' ('a pelo', en castellano).

* No es posible redirigir la 20 KnownDLLs (conocidas


DLLs), que están referenciadas en
HKEY_LOCAL_MACHINE\SYSTEM\CurrentoControlSet\Control\Sessio
nManager\KnownDLLs. Esta no pueden rodar
independientemente ya que necesitan mantener estados de
procesos cruzados. Por ejemplo: kernel32, user32 y ole32
no pueden ser redirigidas debido a que tienen estados
(objetos del kernel, manejadores de ventanas) que
necesitan existir a lo largo de todos los procesos. En
futuras versiones del sistema operativo estas limitaciones
quedarán mas restringidas.



Jose Manuel Tella Llop
MS MVP - DTS


13 - junio - 2001



Jose Manuel Tella Llop
MS MVP - DTS


Este mensaje se proporciona "como está" sin garantías de


ninguna clase, y no otorga ningún derecho.

This posting is provided "AS IS" with no warranties, and


confers no rights.
You assume all risk for your use.





.
eres un gilipollas y escribe de marera que no tengamos


que seguir y dar a la barra de desplazamiento. Tonto de
culo de MS, bestester y mas mierda.

Preguntas similares