Segfo avec 16 caractères en langage C

↓ Il semble qu'il soit populaire récemment de supprimer Python avec une erreur de segmentation. Segfo avec python en trois lignes Segfo avec python en 2 lignes Segfo avec python en une ligne Segfo avec 33 caractères en Python Segfo avec Python en une ligne sans utiliser de ctypes Segfo avec Rust en 5 lignes Le simple fait de changer le sujet (Python) en C le rend ennuyeux, mais c'est la même chose.

code

Opération confirmée avec gcc 10.1.0 (un avertissement apparaît)

*a;main(){*a=0;}
> gcc segf.c
segf.c:3:4:avertissement:La définition de données n'a pas de type ni de classe de stockage
    3 |    *a;main(){*a=0;}
      |    ^
segf.c:3:5:avertissement:Le type sera dans la déclaration de «a» à la valeur par défaut «int»[-Wimplicit-int]
    3 |    *a;main(){*a=0;}
      |     ^
segf.c:3:7:avertissement:Définir le type de retour comme "int" par défaut[-Wimplicit-int]
    3 |    *a;main(){*a=0;}
      |       ^~~~
> ./a.out
zsh: segmentation fault (core dumped)  ./a.out

** Attention ** Actuellement, le nombre minimum de caractères pouvant être utilisés pour le langage C est de 5 caractères. (Voir les commentaires ci-dessous)

Bref commentaire

Cela seul ne répond pas aux exigences de l'article de Qiita, je vais donc l'expliquer brièvement. Le premier code à voir est ↓.

int main(void) {
    int *a = 0;
    *a = 0;  //← Tomber ici
    return 0;
}

Le langage C a un concept appelé pointeur, qui vous permet d'accéder à n'importe quelle adresse en mémoire. Déclarez un pointeur nommé ʻa à ʻint * a = 0 et attribuez l'adresse mémoire 0. Attribuer une valeur à «* a» dans la deuxième ligne accédera à une adresse [^ 1] qui n'existe pas réellement, et une exception CPU se produira.

Codage court

Maintenant, raccourcissons le code ci-dessus. Premièrement, «return 0» peut être omis selon la convention du langage C. [^ 5] De plus, le type de retour ʻint peut être omis du point de vue de la compatibilité. (S'il est omis, il est implicitement ʻint.) De plus, il fonctionne sans écrire l'argument void. Sur la base de ces derniers, c'est comme suit.

 main() {
    int *a = 0;
    *a = 0;  //← Tomber ici
}

Ici, la variable locale «a» peut être définie comme une variable globale. De plus, si vous la définissez comme une variable globale, elle sera initialisée avec «0» (sauf s'il s'agit d'un environnement très spécial), donc aucune affectation pour l'initialisation n'est requise [^ 6].

int *a;
main() {
    *a = 0;  //← Tomber ici
}

De plus, le spécificateur de type de variable globale ʻint` peut être omis. Ceci est le code au début.

prime. L'adresse «* (0p00000000)» existe-t-elle vraiment?

Dans un ordinateur classique, la mémoire est un appareil qui peut stocker de nombreuses informations. Cependant, pour envoyer beaucoup d'informations à la mémoire ou les recevoir de la mémoire, intuitivement, il faut autant de fils que le nombre d'informations que vous souhaitez envoyer et recevoir. Cependant, il n'est pas possible en termes de coût de préparer beaucoup de fils fins pouvant supporter la vitesse de fonctionnement du CPU, nous allons donc introduire le concept d'adresse mémoire. En conséquence, bien que le nombre d'informations pouvant être lues et écrites en même temps (appelé 1 octet) [^ 2] soit petit, beaucoup d'informations peuvent être stockées dans la mémoire en modifiant l'adresse mémoire.

De cette manière, le concept d'adresse mémoire est indispensable à l'ère de la grande capacité mémoire, mais comme il est représenté par un entier positif commençant par "0", l'adresse "0" existe réellement. .. Ensuite, la raison pour laquelle l'erreur de segmentation s'est produite est due à la fonction CPU appelée pagination utilisée par le système d'exploitation.

Les adresses mémoire sont uniques sur un ordinateur. Par conséquent, sauf indication contraire, plusieurs processus posséderont le même espace d'adressage mémoire dans un système d'exploitation multitâche. Dans ce cas, lors de l'accès à la mémoire, vous devez faire attention à ne pas accéder accidentellement à la mémoire utilisée par d'autres processus. La pagination élimine cet inconvénient, permettant à chaque processus de posséder son propre espace d'adressage virtuel. À ce stade, le système d'exploitation gère une table qui convertit entre l'espace d'adressage virtuel [^ 3] et l'espace d'adressage physique (mémoire).

Par conséquent, le processus doit pouvoir accéder à toutes les adresses existantes. Cependant, ce n'est pas le cas dans la réalité, et le système d'exploitation tire également parti de l'espace d'adressage virtuel. Il limite la plage de mémoire disponible pour le programme. Ce type de division de l'espace d'adressage virtuel est appelé une carte mémoire. Comme indiqué dans cet article, la zone autour de l'adresse 0 n'est pas utilisée (l'adresse mémoire physique correspondante n'est pas attribuée), donc Un défaut de segmentation se produira. [^ 4]

en conclusion

Il m'a fallu environ 20 minutes pour l'écrire à la légère. J'aurais dû l'écrire.

[^ 1]: voir ci-dessous. [^ 2]: En fait, 64 bits peuvent être écrits dans chaque module de mémoire en même temps. De plus, la mémoire est accessible à grande vitesse en utilisant des technologies telles que DMA. [^ 3]: et espace d'adressage linéaire [^ 4]: Cela dépend de la façon dont le système d'exploitation est implémenté. En outre, selon le système d'exploitation, une autre exception de processeur se produira. [^ 5]: Beaucoup de gens pensent à tort qu'omettre «return 0;» est une erreur. [^ 6]: Ce n'est pas grave si vous ne l'initialisez pas car cela ne provoque que Segfo.

Recommended Posts

Segfo avec 16 caractères en langage C
Segfo avec 0 caractères avec gcc
Segfo Python avec 33 caractères
Tri de tas fait en langage C
Test de module multi-instance en langage C
Réaliser une classe d'interface en langage C
Ecriture du langage C avec Sympy (métaprogrammation)
Liste de liens (list_head / queue) en langage C
Générer un langage C à partir d'une expression S avec Python
Communiquez avec les périphériques I2C sous Linux C
Méthode de contrôle exclusive multi-processus en langage C
Configurer un serveur UDP en langage C
Créer une image avec des caractères avec python (japonais)
Installez le module dépendant du langage C de python au format roue avec une construction en plusieurs étapes
Gérer les signaux en langage C
Essayez de créer un module Python en langage C
En forme de conteneur réalisé avec C # 1
Débogage C / C ++ avec gdb
Accéder à MongoDB en C
Essayez d'incorporer Python dans un programme C ++ avec pybind11
Next Python en langage C
[Algorithme de langage C] Endianness
API C en Python 3
Aller à la langue pour voir et se souvenir du langage Partie 7 C en langage GO
Accédez au champ de structure C avec le nom réservé dans Go.
Comportement dans chaque langue lorsque les collouts sont réutilisés avec for
J'ai essayé d'illustrer le temps et le temps du langage C
[Algorithme de langage C] bloquer le mouvement
Étendre python en C ++ (Boost.NumPy)
Utilisation de X11 avec ubuntu18.04 (langage C)
100 coups de traitement du langage avec Python 2015
Exploitez LibreOffice avec Python
Grattage avec chromedriver en python
Essayez Google Mock avec C
Utiliser des expressions régulières en C
Gérer les sons en Python
Grattage avec du sélénium en Python
Imiter Numpy de Python en C #
Recherche binaire en Python / C ++
Grattage avec Tor en Python
Combiné avec ordinal en Python
Hello World en langue GO
[Langage C] readdir () vs readdir_r ()
Segfo python en 2 lignes
Formater la source du langage C avec pycparser
Recherche linéaire ALDS1_4_A en langage C
Arborescence de surface totale minimale en C #
Introduction à l'API Socket apprise en langage C, partie 1, édition serveur
C> opération de chaîne> Implémentation à mettre dans char [] avec le chiffre spécifié
Dockerfile avec les bibliothèques nécessaires pour le traitement du langage naturel avec python
Utilisons le modèle de conception comme le langage C avec OSS design_pattern_for_c!
Ecrire une liste de liens en langage C dans un style orienté objet (avec comparaison de code entre Python et Java)