30 votes

Pourquoi l'accès à la mémoire dans l'espace d'adressage le plus faible (bien que non nul) soit signalé comme exception NullReferenceException par .NET?

Cela provoque un AccessViolationException à être jeté:

 using System;

namespace TestApplication
{
    internal static class Program
    {
        private static unsafe void Main()
        {
            ulong* addr = (ulong*)Int64.MaxValue;
            ulong val = *addr;
        }
    }
}
 

Cela provoque un NullReferenceException à être jeté:

 using System;

namespace TestApplication
{
    internal static class Program
    {
        private static unsafe void Main()
        {
            ulong* addr = (ulong*)0x000000000000FF;
            ulong val = *addr;
        }
    }
}
 

Ils sont tous deux des pointeurs non valides et violent tous les deux les règles d'accès à la mémoire. Pourquoi l'exception NullReferenceException?

43voto

Hans Passant Points 475940

Ceci est causé par un design Windows décision prise il y a plusieurs années. Le fond de 64 kilo-octets de l'adresse de l'espace est réservé. Un accès à toutes les adresses dans cette gamme est signalé par une référence null exception au lieu de la sous-jacentes violation d'accès. C'était un choix judicieux, un pointeur null peut produire de la lecture ou de l'écriture à des adresses qui ne sont pas réellement de zéro. La lecture d'un champ d'une classe C++ objet par exemple, il a un décalage à partir du début de l'objet. Si l'objet pointeur est null, le code de la bombe de la lecture à une adresse qui est plus grand que 0.

C# n'est pas tout à fait le même problème, la langue garantit qu'une référence null est pris avant que vous pouvez appeler une méthode d'une instance d'une classe. Ce n'est cependant spécifique à une langue, ce n'est pas une fonction CLR. Vous pouvez écrire du code managé en C++/CLI et de générer des non-zéro de pointeur null déréférence. Appel d'une méthode sur un nullptr objet de travaux. Cette méthode gaiement exécuter. Et d'appeler d'autres méthodes d'instance. Jusqu'à ce qu'il tente d'accéder à une variable d'instance ou d'appel d'une méthode virtuelle, ce qui nécessite un déréférencement ce, kaboom ensuite.

Le C# de garantie est très agréable, il fait le diagnostic de référence null problèmes beaucoup plus facile puisqu'ils sont générés sur le site d'appel et de ne pas la bombe quelque part à l'intérieur d'une méthode imbriquée. Et il est beaucoup plus sûr, la variable d'instance peut ne pas déclencher une exception de très grande taille des objets lors de son décalage est supérieure à 64 ko. Assez difficile à faire dans le code managé btw, à la différence de C++. Mais ne vient pas gratuitement, a expliqué dans ce billet de blog.

17voto

Raymond Chen Points 27887

Une référence nulle exception et une exception de violation d'accès sont à la fois soulevée par le PROCESSEUR comme une violation d'accès. Le CLR ensuite deviner si la violation d'accès doit être spécialisée pour une référence nulle exception ou la gauche comme la plus générale de violation d'accès.

Il est évident à partir de vos résultats que le CLR en déduit que les violations d'accès à des adresses très proche de 0 sont causés par une référence nulle. Parce qu'ils ont presque certainement généré par une référence null, plus le champ de décalage. Votre utilisation du code unsafe imbéciles de cette heuristique.

3voto

David Lively Points 16026

Cela peut être un problème de sémantique.

Votre premier exemple tente de déréférencer un pointeur dont le contenu est l' adresse Int64.MaxValue, et non un pointeur sur une variable dont la valeur est Int64.MaxValue.

On dirait que vous essayez de lire la valeur stockée à l'adresse Int64.MaxValue, qui n'apparaît apparemment pas dans la plage appartenant à votre processus.

Voulez-vous dire quelque chose comme ça?

         static unsafe void Main(string[] args)
        {
            ulong val = 1;// some variable space to store an integer
            ulong* addr = &val;
            ulong read = *addr;

            Console.WriteLine("Val at {0} = {1}", (ulong)addr, read);

#if DEBUG 
            Console.WriteLine("Press enter to continue");
            Console.ReadLine();
#endif
        }
 

2voto

Damith Points 32311

à partir de http://msdn.microsoft.com/en-us/library/system.accessviolationexception.aspx

Les Informations De Version

Cette exception est de nouveau dans le .NET Framework version 2.0. En plus tôt versions de la .NET Framework, une violation d'accès dans le code non managé ou dangereux du code managé est représenté par une NullReferenceException dans code managé. Une exception NullReferenceException est également renvoyée lorsqu'une valeur null de référence est déréférencé en vérifiables code managé, un événement qui n'implique pas la corruption de données, et il n'y a aucun moyen de la distinction entre les deux situations dans les versions 1.0 ou 1.1.

Les administrateurs peuvent autoriser les applications sélectionnées pour revenir à l' le comportement de l' .NET Framework version 1.1. Placez la ligne suivante dans la section de l'Élément du fichier de configuration pour l' application:

autres <legacyNullReferenceExceptionPolicy enabled = "1"/>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X