<?xml version="1.0" encoding="ISO-8859-1"?>

<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
	<channel>
		<title>Forum du club des développeurs et IT Pro - C#</title>
		<link>https://www.developpez.net/forums/</link>
		<description><![CDATA[Forum d'entraide sur la programmation C#. Avant de poster -> FAQ C#, Articles C#, Sources C#]]></description>
		<language>fr</language>
		<lastBuildDate>Wed, 03 Jun 2026 23:45:04 GMT</lastBuildDate>
		<generator>vBulletin</generator>
		<ttl>15</ttl>
		<image>
			<url>https://forum.developpez.be/images/misc/rss.png</url>
			<title>Forum du club des développeurs et IT Pro - C#</title>
			<link>https://www.developpez.net/forums/</link>
		</image>
		<item>
			<title>Améliorer la sécurité de la mémoire en C#, par Richard Lander</title>
			<link>https://www.developpez.net/forums/showthread.php?t=2183873&amp;goto=newpost</link>
			<pubDate>Mon, 25 May 2026 16:03:37 GMT</pubDate>
			<description>*Améliorer la sécurité de la...</description>
			<content:encoded><![CDATA[<div><b><font size="4">Améliorer la sécurité de la mémoire en C#, Richard Lander</font></b><br />
<br />
C# est un langage de programmation de haut niveau à usage général prenant en charge plusieurs paradigmes. C# englobe le typage statique,&#8202; le typage fort, la portée lexicale, la programmation impérative, déclarative, fonctionnelle, générique,&#8202; orientée objet (basée sur les classes) et orientée composants.<br />
<br />
Les principaux concepteurs du langage de programmation C# étaient Anders Hejlsberg, Scott Wiltamuth et Peter Golde, de Microsoft. Il a été largement diffusé pour la première fois en juillet 2000 et a ensuite été approuvé comme norme internationale par l'Ecma (ECMA-334) en 2002 et par l'ISO/IEC (ISO/IEC 23270 et 20619) en 2003. Microsoft a lancé C# en même temps que le .NET Framework et Microsoft Visual Studio, qui sont tous deux, techniquement parlant, des logiciels à code source fermé. À l'époque, Microsoft ne proposait aucun produit open source. Quatre ans plus tard, en 2004, un projet libre et open source appelé Mono a vu le jour, fournissant un compilateur multiplateforme et un environnement d'exécution pour le langage de programmation C#. Une décennie plus tard, Microsoft a lancé Visual Studio Code (éditeur de code), Roslyn (compilateur) et la plateforme .NET unifiée (framework logiciel), qui prennent tous en charge C# et sont gratuits, open source et multiplateformes. Mono a également rejoint Microsoft, mais n'a pas été intégré à .NET. <br />
<br />
Nous sommes en train d’améliorer considérablement la sécurité de la mémoire en C#. Le mot-clé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> est en cours de refonte afin d’indiquer aux appelants qu’ils ont des obligations à respecter pour garantir la sécurité, documentées via un nouveau style de commentaire de sécurité. Le champ d’application de ce mot-clé s’étendra du simple marquage des pointeurs à tout code interagissant avec la mémoire d’une manière que le compilateur ne peut pas valider comme sûre. Le compilateur veillera à ce que le mot-clé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> soit utilisé pour encapsuler les opérations non sécurisées. Il en résultera que les contrats et les hypothèses de sécurité deviendront visibles et vérifiables, au lieu d’être simplement implicites par convention.<br />
<br />
Nous prévoyons de publier le nouveau modèle et la nouvelle syntaxe (officiellement une fonctionnalité de C# 16) en avant-première dans .NET 11 et en version finale dans .NET 12. Cette fonctionnalité sera initialement optionnelle et pourrait devenir la valeur par défaut dans une version ultérieure. Nous mettrons à jour les modèles pour activer le nouveau modèle, tout comme nous l’avons fait avec les types de référence nullables. La première implémentation du compilateur a été intégrée dans la branche principale et prend forme.<br />
<br />
C# 1.0 a introduit le mot-clé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> comme moyen d’établir un contexte non sécurisé sur les types, les méthodes et les blocs de méthodes internes, permettant aux développeurs de choisir la portée la plus pratique. Un contexte non sécurisé accorde l’accès aux fonctionnalités des pointeurs. Une méthode marquée comme <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> peut utiliser ces fonctionnalités dans sa signature et son implémentation, contrairement aux méthodes non marquées. Nous avons également exposé un ensemble de types « unsafe » tels que System.Runtime.CompilerServices.Unsafe et System.Runtime.InteropServices.Marshal, dont l’utilisation devait être prudente par convention.<br />
<br />
Le mot-clé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> a depuis été réutilisé et réinterprété dans Rust et Swift, où les équipes de ces langages lui ont donné une sémantique plus stricte, axée sur la propagation. C# 16 suit la même voie, applique <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> de manière uniforme (y compris sur les membres <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Unsafe</span> et <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Marshal</span>) dans les bibliothèques d'exécution .NET, et ressemble le plus à l'implémentation de Rust. Résultat : <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> cesse de marquer un type de syntaxe et commence à marquer un type de contrat ; un contrat que le compilateur ne peut pas vérifier, mais qu'un développeur expérimenté doit lire et respecter.<br />
<br />
C# bloque déjà le code unsafe par défaut. La plupart des développeurs ne remarqueront aucun changement lorsqu’ils activeront le nouveau modèle, car ils n’activent ni n’utilisent pas d’API unsafe. Le blocage par défaut couvrira une surface beaucoup plus large lorsque le modèle de sécurité de C# 16 sera activé. Le nouveau modèle établit des garde-fous solides qui sont visibles, vérifiables et appliqués par le compilateur. C’est également un outil important pour faire respecter les normes d’ingénierie et de la chaîne d’approvisionnement. La sécurité de la mémoire est une priorité croissante dans l’industrie et au sein des administrations depuis plusieurs années, et la génération de code assistée par l’IA ajoute une nouvelle dimension à mesure que la production de logiciels s’accélère plus vite que la révision humaine.<br />
<br />
<b><font size="3">Sécurité</font></b><br />
<br />
Un article précédent traite des mécanismes de sécurité structurelle dans .NET :<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Citation:</div>
	<div class="bbcode_quote printable">
		<hr />
		
			la sécurité est appliquée par une combinaison du langage et du runtime… Les variables font référence à des objets actifs, sont nulles ou sont hors de portée. La mémoire est auto-initialisée par défaut, de sorte que les nouveaux objets n'utilisent pas de mémoire non initialisée. La vérification des limites garantit que l'accès à un élément avec un index invalide ne permettra pas de lire de la mémoire indéfinie — souvent causée par des erreurs de décalage d'un — mais entraînera à la place une exception <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">IndexOutOfRangeException</span>.
			
		<hr />
	</div>
</div>C# intègre une application stricte des règles de sécurité pour un code sûr standard. Le nouveau modèle permet aux développeurs et aux agents de marquer avec précision les limites de sécurité dans le code non sécurisé. Il existe deux raisons d'écrire du code non sécurisé : l'interopérabilité avec du code natif et, dans certains cas, pour des raisons de performances. Go, Rust et Swift incluent également un dialecte non sécurisé pour ces cas. Le langage ne peut généralement pas vous aider à écrire du code non sécurisé ; son rôle est d'indiquer clairement où le code non sécurisé est utilisé et comment il revient vers du code sécurisé.<br />
<br />
La sécurité en programmation est peut-être plus facile à comprendre si l’on prend un autre domaine comme exemple. Les concepteurs de routes améliorent la sécurité en peignant des lignes continues jaunes ou blanches qui interdisent de passer sur la voie opposée. Les conducteurs comprennent et respectent cette convention. Les autoroutes à grande vitesse utilisent des barrières pour assurer la sécurité grâce à une séparation structurelle qui continue de fonctionner même en l’absence de respect des règles. L’exemple de l’autoroute nous montre que des vitesses plus élevées s’accompagnent de risques plus importants.<br />
<br />
La programmation a ses propres types d’accidents, liés à la mémoire. Chaque application a potentiellement accès à des gigaoctets de mémoire virtuelle. Écrire ou lire dans une mémoire arbitraire entraîne un comportement arbitraire (le terme technique est « comportement indéfini », ou UB) et est la cause de la plupart des bogues de sécurité. L’accès à une mémoire arbitraire n’est pas possible dans un code sûr, mais reste une possibilité omniprésente dans un code non sûr.<br />
<br />
<b><font size="3">Le modèle en bref</font></b><br />
<br />
Les programmes .NET doivent respecter une invariante fondamentale : tout accès à la mémoire doit viser de la mémoire active, c'est-à-dire de la mémoire allouée, initialisée et disponible au moment de l'accès. Le code sécurisé garantit cela de par sa conception : les règles du compilateur et les vérifications d'exécution se combinent pour rendre impossible tout accès erroné. Le code non sécurisé désigne toute opération susceptible de violer cette invariante, généralement en lisant ou en écrivant dans de la mémoire qui n'est pas active, ou en laissant la mémoire dans un état où un accès ultérieur échouera.<br />
<br />
Le code non sécurisé peut lire ou écrire dans de la mémoire arbitraire accessible via l'interopérabilité, par <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">NativeMemory</span>, ou gérée manuellement par le développeur. L'invariante doit néanmoins être respectée. Le compilateur ne peut pas détecter d'UB dans ce cas, la charge de la validation incombe donc au développeur.<br />
<br />
La solution à ce risque consiste en un ensemble de mécanismes en couches qui propagent de manière intentionnelle et transparente l'insécurité à travers le graphe d'appel, chaque couche permettant à la suivante de fonctionner :<br />
<br />
1. <b>Bloc inner <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span> <span class="br0">&#123;</span> <span class="br0">&#125;</span></span></b> : toute opération non sécurisée (appel d'un membre <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>, déréférencement d'un pointeur et autres actions non sécurisées) doit apparaître à l'intérieur d'un bloc inner <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span> <span class="br0">&#123;</span> <span class="br0">&#125;</span></span>. Il s'agit du mécanisme de base. Les opérations non sécurisées sont marquées syntaxiquement, ont une portée définie et sont vérifiables.<br />
<br />
2. <b>Propagation</b> : l'ajout de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> à la signature de la méthode englobante republie les obligations du bloc interne à ses propres appelants, à moins qu'elles ne soient levées. Cela scinde le graphe d'appel en méthodes sûres, méthodes <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> et méthodes de frontière entre elles. Les développeurs peuvent enchaîner la propagation à travers un nombre illimité d'intermédiaires jusqu'à ce que quelqu'un décide de l'arrêter.<br />
<br />
3. <b>Documentation de sécurité</b> : chaque élément <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> doit comporter un bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #808080;">/// &lt;safety&gt;</span></span> : le contrat formel entre l'appelé et l'appelant. Sa rédaction est une bonne pratique fortement encouragée, et les analyseurs peuvent signaler son absence.<br />
<br />
4. <b>Suppression à la frontière</b> : une méthode qui contient un bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> interne mais ne marque pas sa propre signature comme <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> constitue la frontière entre le code unsafe et le code safe. Elle s'acquitte des obligations documentées de l'appelé, par le biais de gardes d'exécution sur les entrées, de raisonnements statiques ou d'invariants documentés provenant d'API en amont (par exemple, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">malloc</span> garantissant que le pointeur renvoyé est valide pour au moins <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">size</span> octets). C'est cette exécution correcte qui rend les appelants sûrs réellement sûrs.<br />
<br />
Il faut parcourir chaque couche pour en tirer la valeur. Si vous ne faites que la moitié du travail, vous n'obtiendrez bien moins de la moitié de la valeur. Parcourez correctement chaque couche et vous disposerez d'un raisonnement cohérent à travers un graphe d'appels que d'autres pourront examiner et éventuellement améliorer.<br />
<br />
L'écriture de code non sécurisé est une compétence particulière qui nécessite une solide compréhension de cet invariant et de nombreux pièges. Le nouveau modèle facilite le raisonnement et la révision du code non sécurisé, mais pas son écriture — il impose une structure formelle et visible. Les mots-clés et l'application par le compilateur ne constituent pas la sécurité ; ils sont l'échafaudage qui permet aux développeurs de l'articuler et de la respecter.<br />
<br />
C# 1.0 regroupait une catégorie de « fonctionnalités de pointeurs » sous <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> : la déclaration et la déréférencement de types de pointeurs, la récupération de l'adresse de variables, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">stackalloc</span></span> vers un pointeur, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">sizeof</span></span> sur des types arbitraires, et d'autres capacités ajoutées au fil des ans, y compris la suppression de certaines erreurs de compilation. Le nouveau modèle est plus sélectif.<br />
<br />
Les changements par rapport aux règles de C# 1.0 incluent :<br />
<br />
- Le modificateur de type <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> génère une erreur. La portée unsafe est désormais limitée aux méthodes, propriétés et champs individuels, où son contrat est visible et spécifié de manière plus concise. Les délégués ne peuvent pas non plus être unsafe car ils sont de type défini.<br />
<br />
- <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> n'est pas autorisé sur les constructeurs statiques ou les finaliseurs. Leurs invocations ne présentent pas de modèle de site d'appel pouvant être encapsulé dans un bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span> <span class="br0">&#123;</span> <span class="br0">&#125;</span></span>, de sorte que le marqueur de signature n'a rien à propager.<br />
<br />
- La contrainte générique <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">new</span><span class="br0">&#40;</span><span class="br0">&#41;</span></span> ne correspond qu'à un constructeur sans paramètre sûr ; un type dont le constructeur sans paramètre est <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> ne peut pas satisfaire <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">new</span><span class="br0">&#40;</span><span class="br0">&#41;</span></span>.<br />
<br />
- Un nouveau mot-clé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">safe</span> permet à un développeur d’attester qu’une déclaration est correcte lorsque le compilateur exige que ce choix soit explicite. À l’heure actuelle, le seul cas de figure concerné est celui des déclarations <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">extern</span>, qui doivent être marquées <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">safe</span> ou <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>, y compris les déclarations de méthodes partielles <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">LibraryImport</span>.<br />
<br />
- L’utilisation de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> sur un membre n’établit plus un contexte non sécurisé. Des blocs <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> internes sont désormais requis aux sites d’appel non sécurisés.<br />
<br />
- Les types de pointeurs dans les signatures ne propagent plus la non-sécurité. Seules les déréférencements de pointeurs sont non sécurisés ; ainsi, un paramètre de type <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">byte</span>*</span> ne propage pas en soi la non-sécurité à ses appelants. Pour le nouveau code, évitez <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">IntPtr</span> pour les pointeurs ; privilégiez les pointeurs typés comme <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">byte</span>*</span>, ou <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">void</span>*</span> pour les pointeurs véritablement opaques. Pour les API existantes basées sur <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">IntPtr</span>, envisagez d’ajouter des surcharges de type pointeur et de masquer ou de rendre obsolètes les versions <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">IntPtr</span>. Pour les descripteurs opaques, privilégiez <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">SafeHandle</span>. <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">nint</span> et <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">IntPtr</span> sont indiscernables dans les métadonnées ; par conséquent, lorsqu'un paramètre est véritablement un entier de taille native, indiquez-le explicitement.<br />
<br />
L'adoption se fait via une nouvelle propriété au niveau du projet, accessible par option. Voir Option au niveau du projet pour plus de détails.<br />
<br />
<b><font size="3">Le modèle en pratique</font></b><br />
<br />
Un code non sécurisé augmente considérablement les risques et présente toujours des limites illimitées dans une certaine mesure. Les meilleures API non sécurisées sont conçues pour réduire au maximum ces limites illimitées : elles intègrent tout ce qu'elles peuvent dans la signature, traitent tout ce qu'elles peuvent dans le corps de la fonction, et laissent à l'appelant un résidu restreint et bien défini à gérer lui-même.<br />
<br />
La méthode <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Encoding.GetString<span class="br0">&#40;</span><span style="color: #0000ff;">byte</span>*, <span style="color: #0000ff;">int</span><span class="br0">&#41;</span></span> en est un bon exemple.<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">unsafe</span> <span style="color: #0000ff;">string</span> GetString<span class="br0">&#40;</span><span style="color: #0000ff;">byte</span>* bytes, <span style="color: #0000ff;">int</span> byteCount<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    ArgumentNullException.ThrowIfNull<span class="br0">&#40;</span>bytes<span class="br0">&#41;</span>;
&nbsp;
    ArgumentOutOfRangeException.ThrowIfNegative<span class="br0">&#40;</span>byteCount<span class="br0">&#41;</span>;
&nbsp;
    <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">string</span>.CreateStringFromEncoding<span class="br0">&#40;</span>bytes, byteCount, <span style="color: #0000ff;">this</span><span class="br0">&#41;</span>;
<span class="br0">&#125;</span></pre></td></tr></table></code><hr />
</div><br />
<br />
La méthode indique clairement ce qu'attend l'API : le paramètre <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">byte</span>*</span> spécifie un tampon brut non géré, et la valeur associée <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">byteCount</span> précise exactement le nombre d'octets que l'API va lire. Le corps de la méthode gère ce qu'il peut : un pointeur nul ou une longueur négative sont rejetés et provoquent une exception. Les conditions de sécurité éliminent un sous-ensemble de cas où <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">string</span>.CreateStringFromEncoding</span> lirait silencieusement de la mémoire arbitraire. <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">GetString</span> renvoie une nouvelle chaîne, éliminant ainsi tout problème d'aliasing ou de durée de vie lié au tampon.<br />
<br />
L'appelant n'a qu'une seule obligation stricte : les <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">byteCount</span> octets commençant à l'adresse <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">bytes</span> doivent correspondre à de la mémoire lisible. Passer une longueur supérieure à celle du tampon entraîne un comportement indéfini : le décodeur peut rencontrer de la mémoire illisible et planter, ou il peut lire tout ce qui se trouve au-delà de la fin et renvoyer une chaîne construite à partir d'octets étrangers arbitraires. Dans le modèle existant, c'est le <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">byte</span>*</span> dans la signature qui empêche cette API d'être appelée depuis du code sûr. Dans le nouveau modèle, un pointeur dans une signature n'implique plus en soi un manque de sécurité ; <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">GetString</span> sera explicitement annoté comme <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> afin qu'il reste inaccessible depuis du code sécurisé.<br />
<br />
« Mieux non sécurisé » ne se définit pas par plus ou moins dangereux, mais par plus ou moins descriptif du manque de sécurité ; les couteaux tranchants coupent le mieux, tandis que les couteaux émoussés déchirent.<br />
<br />
<i>Marshal.ReadByte</i> est un cas qui appelle davantage à la prudence.<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">unsafe</span> <span style="color: #0000ff;">byte</span> ReadByte<span class="br0">&#40;</span>IntPtr ptr, <span style="color: #0000ff;">int</span> ofs<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    <span style="color: #0000ff;">try</span>
    <span class="br0">&#123;</span>
        <span style="color: #0000ff;">byte</span>* addr = <span class="br0">&#40;</span><span style="color: #0000ff;">byte</span>*<span class="br0">&#41;</span>ptr + ofs;
        <span style="color: #0000ff;">return</span> *addr;
    <span class="br0">&#125;</span>
    <span style="color: #0000ff;">catch</span> <span class="br0">&#40;</span>NullReferenceException<span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> AccessViolationException<span class="br0">&#40;</span><span class="br0">&#41;</span>;
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></code><hr />
</div><br />
<br />
Les appelants de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Marshal.ReadByte</span> transmettent un <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">IntPtr</span> et un décalage qui, combinés, désignent un octet que le programme est autorisé à lire. La différence importante par rapport à <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">GetString</span> réside dans le fait que <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ReadByte</span> n'effectue aucune validation des entrées et peut aujourd'hui être appelée à partir de code sécurisé. La clause <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">try</span></span>/<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">catch</span></span> n'offre aucune sécurité, mais sert à modifier le type d'exception, et ce pour un seul scénario de comportement incorrect. La raison pour laquelle cela est considéré comme acceptable est que <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Marshal</span> et <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Unsafe</span> sont traditionnellement considérés comme dangereux à appeler.<br />
<br />
Nous pouvons analyser la méthode un peu plus en détail. La signature <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> actuelle de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ReadByte</span> établit un contexte non sécurisé pour l’implémentation, mais ne crée pas de contrat d’appel ni ne documente d’avertissement à l’appelant. Le modèle existant propage l’insécurité via les types de pointeurs dans les signatures, mais <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">IntPtr</span> contourne cette règle ; l’API constitue en fait un contournement des règles relatives aux pointeurs.<br />
<br />
Le nouveau modèle comble cette lacune. Il élargit la notion de non-sécurité pour couvrir toute opération susceptible de violer l'invariance de la mémoire active (et pas seulement les opérations impliquant des types de pointeurs), et fait du marqueur de signature <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> le contrat de membre, avec des blocs non sécurisés internes encapsulant les opérations non sécurisées. Il aligne également le caractère de sécurité d'<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">IntPtr</span> et des pointeurs tels que <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">byte</span>*</span> : les deux peuvent être détenus, assignés et exposés dans des signatures en dehors d'un bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> ; c'est la déréférence du pointeur qui est non sécurisée.<br />
<br />
<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ReadByte</span> change avec le nouveau modèle, selon la maquette suivante :<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #808080;">/// &lt;summary&gt;Reads a single byte from unmanaged memory.&lt;/summary&gt;</span>
<span style="color: #808080;">/// &lt;safety&gt;</span>
<span style="color: #808080;">/// The sum of &lt;paramref name=&quot;ptr&quot;/&gt; and &lt;paramref name=&quot;ofs&quot;/&gt; must address a byte</span>
<span style="color: #808080;">/// the caller is permitted to read.</span>
<span style="color: #808080;">/// &lt;/safety&gt;</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">unsafe</span> <span style="color: #0000ff;">byte</span> ReadByte<span class="br0">&#40;</span>IntPtr ptr, <span style="color: #0000ff;">int</span> ofs<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    <span style="color: #0000ff;">try</span>
    <span class="br0">&#123;</span>
        <span style="color: #0000ff;">byte</span>* addr = <span class="br0">&#40;</span><span style="color: #0000ff;">byte</span>*<span class="br0">&#41;</span>ptr;
        <span style="color: #0000ff;">unsafe</span>
        <span class="br0">&#123;</span>
            <span style="color: #808080;">// SAFETY: relies on caller obligation.</span>
            <span style="color: #0000ff;">return</span> addr<span class="br0">&#91;</span>ofs<span class="br0">&#93;</span>;
        <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
    <span style="color: #0000ff;">catch</span> <span class="br0">&#40;</span>NullReferenceException<span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> AccessViolationException<span class="br0">&#40;</span><span class="br0">&#41;</span>;
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></code><hr />
</div><br />
<br />
Examinons l'implémentation. Le transtypage <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span class="br0">&#40;</span><span style="color: #0000ff;">byte</span>*<span class="br0">&#41;</span>ptr</span> est une manipulation de pointeur, pas une déréférence ; <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">IntPtr</span> et <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">byte</span>*</span> ont la même forme, mais une représentation différente ; les deux ne sont qu’un nombre. Le danger réside dans une seule ligne : <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">return</span> addr<span class="br0">&#91;</span>ofs<span class="br0">&#93;</span></span>. C’est là que le développeur doit s’assurer que <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">addr + ofs</span> pointe vers une mémoire lisible, car l’indexation déréférence cette adresse. <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">byte</span>*</span> &#8594; <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">byte</span></span> nécessite de copier la mémoire de l’adresse du pointeur vers une valeur. C’est là l’opération dangereuse.<br />
<br />
Le nouveau modèle fonctionne parce que la déréférence du pointeur, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">addr<span class="br0">&#91;</span>ofs<span class="br0">&#93;</span></span>, est encapsulée dans un bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>, mettant ainsi en évidence le risque. La signature <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> devient un contrat pour l'appelant, obligeant ce dernier à encapsuler également ses appels dans un bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>, et lui rappelant de consulter la documentation sur la sécurité de l'appelé.<br />
<br />
Une interprétation stricte du « plus petit bloc non sécurisé » placerait l'opération arithmétique <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">+ ofs</span> en dehors du bloc, car l'arithmétique en soi n'est pas une déréférence. Nous préférons garder <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">addr<span class="br0">&#91;</span>ofs<span class="br0">&#93;</span></span> ensemble : l'indexation est l'indirection (<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">addr<span class="br0">&#91;</span><span style="color: #cc66cc;">0</span><span class="br0">&#93;</span></span> est, par spécification, identique à <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">*addr</span>), et le regroupement rend l'adresse exacte lue visible au point d'accès. Nous nous attendons à ce que ce type de choix soit codifié dans les directives de codage non sécurisé au fil du temps.<br />
<br />
Les violations sont des erreurs de compilation, pas des avertissements. Le modèle n'est pas un « système basé sur la confiance ». Prenons l'exemple de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Marshal.ReadByte</span> ci-dessus : il est marqué comme non sécurisé car son implémentation déréférence un pointeur opaque fourni par l'appelant. Dans le nouveau modèle, il continuera d'être marqué comme non sécurisé car il transfère l'obligation de validité du pointeur aux appelants. Cette obligation était auparavant comprise par convention. Le compilateur exige désormais que <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Marshal.ReadByte</span> expose cette obligation sous forme de contrat.<br />
<br />
<b><font size="3">Propagation et suppression</font></b><br />
<br />
Le système de marquage de sécurité mis en place par Rust constitue un bon guide en matière de propagation et de suppression. C# 16 adopte la même approche et la même syntaxe. Le mot-clé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> est utilisé de deux manières. La première consiste en un bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> interne qui encapsule une opération non sécurisée, généralement due à l'appel d'une autre méthode non sécurisée et/ou à la déréférence d'un pointeur. La seconde consiste en un marqueur de signature <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> externe qui définit un contrat d'appel.<br />
<br />
Pour propager l'insécurité à l'appelant, le développeur ajoute <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> à la signature du membre ; pour supprimer l'insécurité en tant que détail d'implémentation, il omet <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>. La présence ou l'absence de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> dans une signature de membre (pour les méthodes comportant un bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> interne) constitue le signal du compilateur pour la propagation ou la suppression. La propagation transmet l'insécurité à l'appelant supérieur, tandis que la suppression limite l'insécurité en offrant une interface compatible avec les appelants sûrs.<br />
<br />
<b><font size="3">Modèle C# 1.0</font></b><br />
<br />
C# 1.0 utilise <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> sur un type ou un membre pour signifier « contexte non sécurisé à partir de ce point ». Cela n’informe ni ne modifie le contrat d’appel. Les pointeurs constituent le seul mécanisme de propagation en C# 1.0. inner <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> peut être utilisé pour restreindre la portée de la non-sécurité.<br />
<br />
Commençons par un code qui est valide aujourd’hui, dans le modèle C# 1.0.<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">void</span> Caller<span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    M<span class="br0">&#40;</span><span class="br0">&#41;</span>;
<span class="br0">&#125;</span>
&nbsp;
<span style="color: #0000ff;">unsafe</span> <span style="color: #0000ff;">void</span> M<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> <span class="br0">&#125;</span></pre></td></tr></table></code><hr />
</div><br />
<br />
<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Caller</span> peut appeler <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span> M</span> sans aucune formalité.<br />
<br />
La raison est double :<br />
<br />
- <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> est utilisé pour créer un bloc inner <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> pour l’ensemble de la méthode, et non pour définir un contrat d’appelant.<br />
- <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">M</span> n’expose pas de pointeurs, et ne propage donc pas l’insécurité.<br />
<br />
Cet exemple est analogue à <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ReadByte</span>. <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Caller</span> pourrait appeler <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ReadByte</span> aussi librement qu'il appelle <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">M</span>. Il ne pourrait pas appeler <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Encoding.GetString</span> de la même manière en raison de l'utilisation de pointeurs.<br />
<br />
Nous devons critiquer le modèle existant pour comprendre pourquoi nous nous en éloignons. Les rôles et responsabilités de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">M</span> et de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Caller</span> ne sont spécifiés que par convention. Il n'existe aucune norme concernant les préoccupations de sécurité ou les obligations que <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">M</span> devrait communiquer à <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Caller</span>, ni sur la manière dont <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Caller</span> répond aux attentes de ses appelants en matière de sécurité. En bref, il n'existe aucun système global qui pousse les développeurs vers une sécurité réelle ou qui permette un audit simple. La sécurité est actuellement assurée par des ingénieurs qualifiés qui savent définir les obligations et les risques, sans l'aide du compilateur.<br />
<br />
<b><font size="3">Modèle C# 16</font></b><br />
<br />
Le nouveau modèle utilise la clé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> dans la signature d'une méthode comme mécanisme de propagation vers l'appelant. L'absence de la clé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> sert à indiquer une suppression.<br />
<br />
La méthode <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Caller</span> de l'exemple précédent devrait être adaptée pour devenir soit <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Caller1</span> , soit <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Caller2</span> ci-dessous.<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #808080;">/// &lt;safety&gt;</span>
<span style="color: #808080;">/// Caller must satisfy obligation 1</span>
<span style="color: #808080;">/// &lt;/safety&gt;</span>
<span style="color: #0000ff;">unsafe</span> <span style="color: #0000ff;">void</span> Caller1<span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    <span style="color: #0000ff;">unsafe</span>
    <span class="br0">&#123;</span>
        <span style="color: #808080;">// SAFETY: Obligation is passed to caller.</span>
        M<span class="br0">&#40;</span><span class="br0">&#41;</span>;
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span style="color: #0000ff;">void</span> Caller2<span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    <span style="color: #0000ff;">if</span> <span class="br0">&#40;</span><span style="color: #808080;">/* obligation 1 not satisfied */</span><span class="br0">&#41;</span> <span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> Exception<span class="br0">&#40;</span><span class="br0">&#41;</span>;
&nbsp;
    <span style="color: #0000ff;">unsafe</span>
    <span class="br0">&#123;</span>
        <span style="color: #808080;">// SAFETY: obligation 1 is discharged by the check above</span>
        M<span class="br0">&#40;</span><span class="br0">&#41;</span>;
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
<span style="color: #808080;">/// &lt;safety&gt;</span>
<span style="color: #808080;">/// Caller must satisfy obligation 1</span>
<span style="color: #808080;">/// &lt;/safety&gt;</span>
<span style="color: #0000ff;">unsafe</span> <span style="color: #0000ff;">void</span> M<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span> <span class="br0">&#125;</span></pre></td></tr></table></code><hr />
</div><br />
<br />
<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">M</span> et <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Caller1</span> propagent toutes deux l'insécurité à leurs appelants. <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Caller2</span> supprime l'insécurité de ses appelés et constitue une méthode de limite unsafe. L'une ou l'autre forme constitue un remplacement valable pour <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Caller</span>. Le développeur décide laquelle est appropriée en fonction de la possibilité ou de l'opportunité de valider l'obligation 1. Si les obligations de l'appelant subsistent, alors <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Caller1</span> est le bon choix. Le choix entre propagation et suppression n'est pas imposé (ni suggéré) par le compilateur, mais nécessite un jugement prudent.<br />
<br />
<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Caller1</span> comporte deux marqueurs <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> par conception : le marqueur externe projette le contrat de l'appelant, tandis que le marqueur interne délimite la portée des opérations <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>. À l'intérieur d'un membre <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>, omettre le bloc non sécurisé interne lors d'une opération non sécurisée entraîne une erreur de compilation ; le marqueur de signature n'établit plus à lui seul un contexte non sécurisé. Cette structure de propagation externe / portée interne correspond à <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span> fn</span> / <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span> <span class="br0">&#123;</span> <span class="br0">&#125;</span></span> de Rust et à <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">@unsafe</span> / <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span> expr</span> de Swift.<br />
<br />
<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Caller2</span> est « safe-callable », n’imposant aucune obligation à ses appelants et ne nécessitant aucun bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> à leurs points d’appel.<br />
<br />
Le modèle s’applique à tout appelant. L’exemple ci-dessus illustre des appelants du même type. Le modèle s’applique de manière uniforme à tous les types, projets et paquets. Il s’applique également aux générateurs de code source. Aucun mécanisme d’exclusion par portée n’est prévu.<br />
<br />
L'application se fait uniquement au moment de la compilation. Le modèle n'introduit aucune nouvelle vérification d'exécution et n'a aucun impact sur les performances ; les vérifications d'exécution existantes qui entraînent des exceptions telles que <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">IndexOutOfRangeException</span> et <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ArgumentNullException</span> restent inchangées.<br />
<br />
Les bibliothèques d'exécution .NET adopteront ce modèle. Cela est nécessaire en tant que base du modèle pour les appelants. L'utilisation d'une bibliothèque qui a adopté ce modèle n'oblige pas votre projet à l'adopter, et vice versa. Le comportement inter-assemblages dépend du côté qui a opté pour l'activation :<br />
<br />
- <b>Appelant ayant opté, appelé ayant opté (Opted-in caller, opted-in callee)</b>. Le nouveau modèle. Les marqueurs <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> de l'appelé sont transmis via les métadonnées, et l'appelant doit encapsuler les appels dans un bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span> <span class="br0">&#123;</span> <span class="br0">&#125;</span></span> ; sans cela, l'appel génère une erreur de compilation.<br />
<br />
- <b>Appelant ayant opté, appelé n'ayant pas opté (hérité) (Opted-in caller, non-opted-in (legacy) callee)</b>. Mode Compat. Le compilateur traite tout membre de l'appelé dont la signature contient un type pointeur comme <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>, ce qui nécessite un bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span> <span class="br0">&#123;</span> <span class="br0">&#125;</span></span> englobant l'appel. Les surfaces non sécurisées non pointeur (paramètres <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">IntPtr</span>/<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">nint</span>, signatures P/Invoke, etc.) ne sont pas signalées, car l'assembly hérité ne contient pas de métadonnées permettant de les distinguer. Le mode Compatibilité empêche une « baisse de sécurité » où les API non sécurisées d’un package hérité perdraient silencieusement leur propagation non sécurisée pilotée par des pointeurs lorsque le nouveau modèle est activé.<br />
<br />
- <b>Appelant n'ayant pas opté, appelé ayant opté (Non-opted-in caller, opted-in callee).</b> Aucune application des marqueurs <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> du nouveau modèle ; l’appelant hérité ne peut pas les interpréter. Les règles de pointeurs héritées de C# 1.0 s'appliquent toujours : un appelé qui expose un type de pointeur dans sa signature exige toujours que l'appelant hérité se trouve dans un contexte <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>. La nouveauté réside dans les méthodes non sécurisées du nouveau modèle qui ne comportent pas de types de pointeurs dans leur signature (par exemple, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span> <span style="color: #0000ff;">byte</span> ReadByte<span class="br0">&#40;</span>IntPtr, <span style="color: #0000ff;">int</span><span class="br0">&#41;</span></span>). Celles-ci deviennent appelables à partir de code sécurisé hérité.<br />
<br />
La migration des bibliothèques d'exécution est déjà en cours : l'étiquette « reduce-unsafe » suit la liste des tickets de pull (PR) supprimant le code non sécurisé des bibliothèques, y compris des remplacements comme le #127394 (remplacement de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">MemoryMarshal.Read</span>/<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Write</span> par des équivalents <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">BitConverter</span>) et le #127485 (suppression du code non sécurisé de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">IBinaryInteger.TryReadBigEndian</span>). Cette migration montre également que le code industriel peut être converti en modèles sécurisés. Votre code non sécurisé le peut probablement aussi.<br />
<br />
Pour résumer les changements par rapport à C# 1.0 :<br />
<br />
- Le mot-clé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> sur la signature d'un membre définit désormais un contrat vis-à-vis de l'appelant qui propage l'insécurité vers le haut de l'arborescence d'appel. Dans C# 1.0, il servait uniquement à établir un contexte non sécurisé.<br />
<br />
- Un bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> est obligatoire à chaque appel à un membre non sécurisé.<br />
<br />
<b><font size="3">Comparaison entre les langages : propagation</font></b><br />
<br />
Les différences entre C#, Rust et Swift sont à la fois subtiles et instructives. C# 16 ne propage l'insécurité que lorsque le mot-clé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> apparaît sur le membre ; les types de pointeurs et autres paramètres de type unsafe ne se propagent pas d'eux-mêmes. Rust se comporte de la même manière : un paramètre <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">*<span style="color: #0000ff;">const</span> u8</span> sur une fonction <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">fn</span> simple ne propage rien. Swift est l'exception : tout type <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">@unsafe</span> apparaissant dans une signature rend implicitement la déclaration <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">@unsafe</span>, en plus de l'attribut explicite <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">@unsafe</span>.<br />
<br />
Le modèle implicite de Swift conduit à la nécessité d’utiliser <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">@safe</span> comme option d’exclusion largement applicable pour les API qui encapsulent l’insécurité (par exemple, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Array.withUnsafeBufferPointer</span>). C# et Rust incluent tous deux une forme de sécurité positive restreinte pour l’interopérabilité (FFI), mais pour des raisons différentes. La fonction <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">safe fn</span> de Rust à l’intérieur d’un bloc extern non sécurisé est une redéfinition de la valeur par défaut. Le bloc est par défaut non sécurisé et safe permet d’exclure une déclaration individuelle, de manière analogue à <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">@safe</span> de Swift. Le <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">safe <span style="color: #0000ff;">extern</span></span> de C# 16 pour les déclarations <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">LibraryImport</span> n’est pas une redéfinition. Il s’agit d’une déclaration concernant l’ensemble de la déclaration et elle est requise car le langage privilégie les marquages explicites et ne permet pas à un développeur de laisser la sécurité d’une déclaration étrangère implicite.<br />
<br />
Chaque méthode partielle <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">LibraryImport</span> doit être marquée comme <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">safe</span> ou <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> :<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br /></div></td><td valign="top"><pre style="margin: 0"><span class="br0">&#91;</span>LibraryImport<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;libc&quot;</span><span class="br0">&#41;</span><span class="br0">&#93;</span>
<span style="color: #0000ff;">internal</span> <span style="color: #0000ff;">static</span> safe <span style="color: #0000ff;">partial</span> <span style="color: #0000ff;">int</span> getpid<span class="br0">&#40;</span><span class="br0">&#41;</span>;
&nbsp;
<span class="br0">&#91;</span>LibraryImport<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;libc&quot;</span>, StringMarshalling = StringMarshalling.Utf8<span class="br0">&#41;</span><span class="br0">&#93;</span>
<span style="color: #0000ff;">internal</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">unsafe</span> <span style="color: #0000ff;">partial</span> nint strlen<span class="br0">&#40;</span><span style="color: #0000ff;">byte</span>* str<span class="br0">&#41;</span>;</pre></td></tr></table></code><hr />
</div><br />
<br />
<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">getpid</span> n’a pas de paramètres et renvoie une primitive ; l’auteur certifie que l’appel est correct et que les appelants peuvent l’utiliser sans crainte. <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">strlen</span> prend un pointeur brut que le code natif déréférencera ; l’auteur n’a aucun moyen de s’acquitter de cette obligation à la limite, donc la déclaration se propage comme <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> et un bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">&lt;safety&gt;</span> nomme l’obligation de l’appelant. Omettre les deux modificateurs entraîne une erreur de compilation — le développeur doit faire un choix.<br />
<br />
Examinons un exemple de propagation. Un court programme Rust (édition 2024) déclenche à la fois un avertissement <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">unsafe_op_in_unsafe_fn</span> (une opération non sécurisée à l’intérieur du corps d’une fonction non sécurisée sans bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> interne) et une erreur E0133 (un appel à une fonction non sécurisée depuis un contexte sécurisé sans bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>) :<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br /></div></td><td valign="top"><pre style="margin: 0">$ cat main.rs
<span style="color: #808080;">/// # Safety</span>
<span style="color: #808080;">///</span>
<span style="color: #808080;">/// `bytes` must be non-null and point to at least one readable byte.</span>
pub <span style="color: #0000ff;">unsafe</span> fn first_byte<span class="br0">&#40;</span>bytes: *<span style="color: #0000ff;">const</span> u8<span class="br0">&#41;</span> -&gt; u8 <span class="br0">&#123;</span>
    <span style="color: #808080;">// No inner `unsafe { }`: warns under `unsafe_op_in_unsafe_fn` (edition 2024).</span>
    *bytes
<span class="br0">&#125;</span>
&nbsp;
fn main<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span style="color: #0000ff;">let</span> data = <span class="br0">&#91;</span>42u8<span class="br0">&#93;</span>;
    <span style="color: #808080;">// No `unsafe { }` around the call: hard error E0133.</span>
    <span style="color: #0000ff;">let</span> <span style="color: #0000ff;">value</span> = first_byte<span class="br0">&#40;</span>data.as_ptr<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;
    println!<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;<span style="color: black;"><span class="br0">&#123;</span><span style="color: #0000ff;">value</span><span class="br0">&#125;</span></span>&quot;</span><span class="br0">&#41;</span>;
<span class="br0">&#125;</span>
&nbsp;
$ cargo build
   Compiling unsafe_demo v0.1.0 <span class="br0">&#40;</span>/<span style="color: #0000ff;">private</span>/tmp/<span style="color: #0000ff;">unsafe</span>-demo<span class="br0">&#41;</span>
warning<span class="br0">&#91;</span>E0133<span class="br0">&#93;</span>: dereference of raw pointer <span style="color: #0000ff;">is</span> <span style="color: #0000ff;">unsafe</span> and requires <span style="color: #0000ff;">unsafe</span> block
 --&gt; src/main.rs:<span style="color: #cc66cc;">6</span>:<span style="color: #cc66cc;">5</span>
  |
<span style="color: #cc66cc;">6</span> |     *bytes
  |     ^^^^^^ dereference of raw pointer
  |
  = note: raw pointers may be <span style="color: #0000ff;">null</span>, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
note: an <span style="color: #0000ff;">unsafe</span> function restricts its caller, but its body <span style="color: #0000ff;">is</span> safe <span style="color: #0000ff;">by</span> <span style="color: #0000ff;">default</span>
 --&gt; src/main.rs:<span style="color: #cc66cc;">4</span>:<span style="color: #cc66cc;">1</span>
  |
<span style="color: #cc66cc;">4</span> | pub <span style="color: #0000ff;">unsafe</span> fn first_byte<span class="br0">&#40;</span>bytes: *<span style="color: #0000ff;">const</span> u8<span class="br0">&#41;</span> -&gt; u8 <span class="br0">&#123;</span>
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  = note: <span style="color: #0000ff;">for</span> more information, see &lt;https:<span style="color: #808080;">//doc.rust-lang.org/edition-guide/rust-2024/unsafe-op-in-unsafe-fn.html&gt;</span>
  = note: `<span style="color: #339933;">#[warn(unsafe_op_in_unsafe_fn)]` (part of `#[warn(rust_2024_compatibility)]`) on by default</span>
&nbsp;
error<span class="br0">&#91;</span>E0133<span class="br0">&#93;</span>: call to <span style="color: #0000ff;">unsafe</span> function `first_byte` <span style="color: #0000ff;">is</span> <span style="color: #0000ff;">unsafe</span> and requires <span style="color: #0000ff;">unsafe</span> block
  --&gt; src/main.rs:<span style="color: #cc66cc;">12</span>:<span style="color: #cc66cc;">17</span>
   |
<span style="color: #cc66cc;">12</span> |     <span style="color: #0000ff;">let</span> <span style="color: #0000ff;">value</span> = first_byte<span class="br0">&#40;</span>data.as_ptr<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;
   |                 ^^^^^^^^^^^^^^^^^^^^^^^^^ call to <span style="color: #0000ff;">unsafe</span> function
   |
   = note: consult the function<span style="color: #FF0000;">'s documentation for information on how to avoid undefined behavior</span>
&nbsp;
<span style="color: #FF0000;">For more information about this error, try `rustc --explain E0133`.</span>
<span style="color: #FF0000;">warning: `unsafe_demo` (bin &quot;unsafe_demo&quot;) generated 1 warning</span>
<span style="color: #FF0000;">error: could not compile `unsafe_demo` (bin &quot;unsafe_demo&quot;) due to 1 previous error; 1 warning emitted</span></pre></td></tr></table></code><hr />
</div><br />
<br />
Cette expérience est très similaire à ce que nous avons prévu. La principale différence est que ces deux cas seront considérés comme des erreurs dans C# 16.<br />
<br />
En résumé, les codes C# et Rust privilégient des règles explicites simples et nécessitent sans doute moins de connaissances du domaine. Un exemple typique est qu’il est raisonnable d’utiliser <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">grep</span> comme outil d’audit de sécurité avec C# 16 et Rust, car les mots-clés explicites agissent comme des repères auxquels les requêtes peuvent facilement s’accrocher.<br />
<br />
<b><font size="3">Opt-in au niveau du projet</font></b><br />
<br />
Le modèle de sécurité de C# 16 comporte deux commutateurs au niveau du projet. Ils sont indépendants et ont des objectifs différents.<br />
<br />
Le premier commutateur est une nouvelle propriété d'activation (dont le nom définitif sera annoncé avec la préversion de .NET 11). Lorsqu'il est désactivé, les règles héritées de C# 1.0 continuent de s'appliquer ; lorsqu'il est activé, les nouvelles règles « caller-unsafe » s'appliquent. Ce commutateur détermine ce qui est considéré comme non sécurisé et comment cela se propage.<br />
<br />
Le deuxième commutateur est la propriété existante <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">&lt;AllowUnsafeBlocks&gt;</span>. Elle est définie par défaut sur <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">false</span></span> (dans toutes les versions de C#) et contrôle chaque occurrence du mot-clé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> dans le code source du projet : signatures de membres, blocs internes, champs et déclarations <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">safe <span style="color: #0000ff;">extern</span></span> selon les nouvelles règles. L'appel d'une API non sécurisée depuis un autre projet est pris en compte, car le site d'appel nécessite un bloc interne unsafe <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span class="br0">&#123;</span> <span class="br0">&#125;</span></span>. Ainsi, un projet avec les paramètres par défaut ne peut utiliser aucune API non sécurisée.<br />
<br />
Ces deux propriétés se combinent comme suit :<br />
<br />
- <b>Nouvelle propriété activée, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">&lt;AllowUnsafeBlocks&gt;</span> désactivée (par défaut).</b> Il s'agit de la configuration la plus sûre. Le projet adhère au nouveau modèle et n'autorise aucun code non sécurisé. Vous savez que votre code n'appelle pas Marshal.ReadByte ni aucun autre membre non sécurisé.<br />
<br />
- <b>Nouvelle propriété activée, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">&lt;AllowUnsafeBlocks&gt;</span> activée.</b> Le projet adhère au nouveau modèle et autorise le code non sécurisé.<br />
<br />
- <b>Nouvelle propriété désactivée, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">&lt;AllowUnsafeBlocks&gt;</span> désactivé.</b> L'ancien modèle continue de s'appliquer. Le projet ne peut pas utiliser de types de pointeurs.<br />
<br />
- <b>Nouvelle propriété désactivée, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">&lt;AllowUnsafeBlocks&gt;</span> activé.</b> L'ancien modèle continue de s'appliquer. Le projet peut utiliser des types de pointeurs.<br />
<br />
Nous souhaitons que tout le monde passe au nouveau modèle. Nous prévoyons également que, avec le temps, moins de projets activeront <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">&lt;AllowUnsafeBlocks&gt;</span>. C'est ce que nous faisons avec notre propre code.<br />
<br />
Pour faciliter cette transition, nous prévoyons de fournir un correcteur de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">dotnet format</span> qui effectuera une migration au mieux de ses capacités sur les projets qui n'ont pas encore activé la nouvelle propriété : en encapsulant les sites d'appel non sécurisés dans des blocs <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span> <span class="br0">&#123;</span> <span class="br0">&#125;</span></span>, en déplaçant le modificateur <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> des types vers leurs membres, et en effectuant d'autres réécritures mécaniques similaires. Le correcteur ne peut pas déduire les obligations de sécurité ni écrire de blocs <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">&lt;safety&gt;</span> ; ce travail reste à la charge du développeur. Il s'agit d'un point de départ permettant de compiler le code selon les nouvelles règles, et non d'une migration achevée.<br />
<br />
La question centrale concernant les agents générateurs de code est de savoir à qui incombe la responsabilité de déterminer si du code non sécurisé a été écrit. Avec le nouveau modèle, c'est celle du compilateur. En supposant que vous n'ayez pas défini <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">AllowUnsafeBlocks=<span style="color: #0000ff;">true</span></span>, le compilateur refusera de compiler tout code non sécurisé. Aucune révision de code ne peut égaler l'efficacité d'une erreur de compilation. L'audit de la sécurité de la mémoire passe de l'inspection de chaque diff à la vérification d'une seule propriété de projet.<br />
<br />
<b><font size="3">Comparaison entre les langages : valeurs par défaut</font></b><br />
<br />
Les différences sont ici aussi subtiles et importantes. Nous pouvons situer les trois langages selon deux axes de sécurité : la propagation stricte (la manière dont l’insécurité se propage et ce qui est considéré comme dangereux) et l’interdiction pure et simple du code dangereux. Pour chaque axe, la posture la plus sûre est soit la valeur par défaut, soit disponible en option.<br />
<br />
<div style="text-align: center;"><img src="https://www.developpez.net/forums/attachments/p676685d1780427508/dotnet/langages/csharp/ameliorer-securite-memoire-csharp-richard-lander/1.jpg/" border="0" alt="Nom : 1.jpg
Affichages : 33
Taille : 31,1 Ko"  style="float: CONFIG" /></div><br />
C# 16 activera le modèle strict avec le nouveau mot-clé safety. <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">AllowUnsafeBlocks=<span style="color: #0000ff;">false</span></span> reste la valeur par défaut. Sous le nouveau modèle, il effectue un travail encore plus lourd, car l'ensemble des actions non sécurisées qu'il contrôle est beaucoup plus vaste.<br />
<br />
Rust ne dispose que d’un seul modèle de sécurité, un modèle strict. Le compilateur autorise par défaut l’utilisation de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> dans n’importe quel crate et nécessite l’utilisation de la directive <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #339933;">#![forbid(unsafe_code)]</span></span> pour le désactiver.<br />
<br />
Swift propose également un mode strict en option (<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">-strict-memory-safety</span>, SE-0458), qui peut être défini par fichier ou par module pour transformer les dangers implicites en diagnostics.<br />
<br />
Ces comparaisons ne sont pas tout à fait équivalentes, car elles sont multidimensionnelles. Rust a la position par défaut la plus stricte. Notre point de vue s’aligne sur le continuum de sécurité mémoire : des valeurs par défaut plus strictes sont préférables. Notre intention est de faire du nouveau modèle de sécurité de C# la nouvelle norme. Nous commencerons par l’activer avec les modèles. Il est plus simple pour nous d’introduire un modèle de sécurité plus strict étant donné que le code non sécurisé est déjà interdit par défaut, et nous nous attendons à une bonne adoption pour cette raison.<br />
<br />
<b><font size="3">Documentation relative à la sécurité</font></b><br />
<br />
Il est facile d’interpréter le terme « non sécurisé » au sens littéral, mais cela prête à confusion. Il signifie « désactiver les mécanismes de sécurité ». Le compilateur sait que le code sécurisé respecte un modèle de sécurité défini, contrairement au code non sécurisé. Avec le code non sécurisé, c’est au développeur qu’incombe la responsabilité de s’informer. Pour s’informer, il faut commencer par lire la documentation dédiée à la sécurité. Un code non sécurisé correctement rédigé documente les obligations de l'appelant : les conditions que celui-ci doit remplir pour que le code se comporte correctement.<br />
<br />
Un code non sécurisé dont la documentation est manquante ou mal rédigée n'est pas sûr à appeler, car l'appelant est laissé dans l'incertitude. Les auditeurs de code y prêtent une attention particulière. C'est déjà le cas dans la communauté Rust : Google et Mozilla.<br />
<br />
Un analyseur signalera les blocs <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #808080;">/// &lt;safety&gt;</span></span> manquants.<br />
<br />
<b><font size="3">Commentaires de sécurité Rust</font></b><br />
<br />
Nous nous appuierons sur Rust pour les exemples canoniques, car ce langage est bien établi. Rust utilise des commentaires de sécurité pour démontrer que le code non sécurisé est correct.<br />
<br />
Une fonction Rust non sécurisée, <i>as_bytes_mut</i> :<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #808080;">/// Converts a mutable string slice to a mutable byte slice.</span>
<span style="color: #808080;">///</span>
<span style="color: #808080;">/// # Safety</span>
<span style="color: #808080;">///</span>
<span style="color: #808080;">/// The caller must ensure that the content of the slice is valid UTF-8</span>
<span style="color: #808080;">/// before the borrow ends and the underlying `str` is used.</span>
<span style="color: #808080;">///</span>
<span style="color: #808080;">/// Use of a `str` whose contents are not valid UTF-8 is undefined behavior.</span>
<span style="color: #808080;">///</span>
<span style="color: #808080;">/// ...</span>
pub <span style="color: #0000ff;">unsafe</span> fn as_bytes_mut<span class="br0">&#40;</span>&amp;mut self<span class="br0">&#41;</span> -&gt; &amp;mut <span class="br0">&#91;</span>u8<span class="br0">&#93;</span> <span class="br0">&#123;</span>
    <span style="color: #808080;">// SAFETY: the cast from `&amp;str` to `&amp;[u8]` is safe since `str`</span>
    <span style="color: #808080;">// has the same layout as `&amp;[u8]` (only libstd can make this guarantee).</span>
    <span style="color: #808080;">// The pointer dereference is safe since it comes from a mutable reference which</span>
    <span style="color: #808080;">// is guaranteed to be valid for writes.</span>
    <span style="color: #0000ff;">unsafe</span> <span class="br0">&#123;</span> &amp;mut *<span class="br0">&#40;</span>self <span style="color: #0000ff;">as</span> *mut str <span style="color: #0000ff;">as</span> *mut <span class="br0">&#91;</span>u8<span class="br0">&#93;</span><span class="br0">&#41;</span> <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></code><hr />
</div><br />
<br />
Clippy applique cette convention. Une fonction non sécurisée sans section <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #339933;"># Safety</span></span> déclenche le lint missing_safety_doc :<br />
<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br /></div></td><td valign="top"><pre style="margin: 0">$ cat main.rs
<span style="color: #339933;">#![deny(clippy::missing_safety_doc)]</span>
&nbsp;
pub <span style="color: #0000ff;">unsafe</span> fn first_byte<span class="br0">&#40;</span>bytes: *<span style="color: #0000ff;">const</span> u8<span class="br0">&#41;</span> -&gt; u8 <span class="br0">&#123;</span>
    <span style="color: #0000ff;">unsafe</span> <span class="br0">&#123;</span> *bytes <span class="br0">&#125;</span>
<span class="br0">&#125;</span>
&nbsp;
fn main<span class="br0">&#40;</span><span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span style="color: #0000ff;">let</span> data = <span class="br0">&#91;</span>42u8<span class="br0">&#93;</span>;
    <span style="color: #0000ff;">let</span> <span style="color: #0000ff;">value</span> = <span style="color: #0000ff;">unsafe</span> <span class="br0">&#123;</span> first_byte<span class="br0">&#40;</span>data.as_ptr<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#125;</span>;
    println!<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;<span style="color: black;"><span class="br0">&#123;</span><span style="color: #0000ff;">value</span><span class="br0">&#125;</span></span>&quot;</span><span class="br0">&#41;</span>;
<span class="br0">&#125;</span>
&nbsp;
$ cargo clippy
    Checking unsafe_demo v0.1.0 <span class="br0">&#40;</span>/<span style="color: #0000ff;">private</span>/tmp/<span style="color: #0000ff;">unsafe</span>-demo<span class="br0">&#41;</span>
error: <span style="color: #0000ff;">unsafe</span> function<span style="color: #FF0000;">'s docs are missing a `# Safety` section</span>
<span style="color: #FF0000;"> --&gt; src/main.rs:3:1</span>
<span style="color: #FF0000;">  |</span>
<span style="color: #FF0000;">3 | pub unsafe fn first_byte(bytes: *const u8) -&gt; u8 {</span>
<span style="color: #FF0000;">  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^</span>
<span style="color: #FF0000;">  |</span>
<span style="color: #FF0000;">  = help: for further information visit https://rust-lang.github.io/rust-clippy/rust-1.95.0/index.html#missing_safety_doc</span>
<span style="color: #FF0000;">note: the lint level is defined here</span>
<span style="color: #FF0000;"> --&gt; src/main.rs:1:9</span>
<span style="color: #FF0000;">  |</span>
<span style="color: #FF0000;">1 | #![deny(clippy::missing_safety_doc)]</span>
<span style="color: #FF0000;">  |         ^^^^^^^^^^^^^^^^^^^^^^^^^^</span>
&nbsp;
<span style="color: #FF0000;">error: could not compile `unsafe_demo` (bin &quot;unsafe_demo&quot;) due to 1 previous error</span></pre></td></tr></table></code><hr />
</div><br />
<br />
Si vous débutez avec Rust, oui, il dispose de commentaires de documentation ///. Il dispose également d’attributs, qui sont utilisés pour les balises de sécurité proposées.<br />
<br />
Le bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #808080;">/// # Safety</span></span> au-dessus de la fonction documente les obligations formelles et contractuelles de l’appelant. Il incombe à l’appelant de lire les commentaires de sécurité. Négliger de le faire peut entraîner l’écriture d’un code non sécurisé incorrect aux conséquences indéfinies. Si des problèmes surviennent, la responsabilité incombe à l’appelant. C’est pourquoi nous qualifions cette fonctionnalité de « non sécurisée pour l’appelant ».<br />
<br />
Les commentaires <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #808080;">///</span></span> sont directement copiés dans la documentation publique de Rust pour as_bytes_mut. Les commentaires de sécurité sont extraits du code et placés sur un portail public où les appelants peuvent les consulter. Cela montre clairement leur importance et explique pourquoi ils doivent être distincts des commentaires habituels.<br />
<br />
L'exemple comprend également un deuxième type de commentaire de sécurité, plus interne. Les notes <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #808080;">// SAFETY:</span></span> à l'intérieur du corps de la fonction s'adressent aux développeurs ou aux auditeurs du code ; elles décrivent les hypothèses de sécurité, et non les obligations de l'appelant. Le compilateur ne lit pas, n'exige pas et ne prend pas en compte ces commentaires. Il s'agit d'une convention.<br />
<br />
Ces deux styles de commentaires sont importants. Ensemble, ils racontent une histoire à double facette sur la sécurité, ancrée dans le graphe d'appel.<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Citation:</div>
	<div class="bbcode_quote printable">
		<hr />
		
			Avec le bloc unsafe, nous affirmons à Rust que nous avons lu la documentation de la fonction, que nous comprenons comment l'utiliser correctement et que nous avons vérifié que nous respectons le contrat de la fonction.
			
		<hr />
	</div>
</div>Cet extrait du Rust Book montre clairement que la sécurité dépend d'un processus qui commence par les diagnostics du compilateur mais ne s'arrête pas là. Le lint Rust correspondant (unsafe_op_in_unsafe_fn) était autorisé par défaut dans les éditions précédentes, de sorte que les blocs <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> internes manquants étaient acceptés sans avertissement. L'édition 2024 l'a promu au statut « warn-by-default », un compromis de compatibilité qui permet aux crates existantes de continuer à se compiler au-delà de la limite entre les éditions. C# 16 n'a pas hérité de cette tradition et en fait une erreur de compilation.<br />
<br />
<b><font size="3">Commentaires de sécurité C#</font></b><br />
<br />
C# utilise deux styles de commentaires de sécurité, illustrés ici dans la maquette <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ReadByte</span> :<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #808080;">/// &lt;summary&gt;Reads a single byte from unmanaged memory.&lt;/summary&gt;</span>
<span style="color: #808080;">/// &lt;safety&gt;</span>
<span style="color: #808080;">/// The sum of &lt;paramref name=&quot;ptr&quot;/&gt; and &lt;paramref name=&quot;ofs&quot;/&gt; must address a byte</span>
<span style="color: #808080;">/// the caller is permitted to read.</span>
<span style="color: #808080;">/// &lt;/safety&gt;</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">unsafe</span> <span style="color: #0000ff;">byte</span> ReadByte<span class="br0">&#40;</span>IntPtr ptr, <span style="color: #0000ff;">int</span> ofs<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    <span style="color: #0000ff;">try</span>
    <span class="br0">&#123;</span>
        <span style="color: #0000ff;">byte</span>* addr = <span class="br0">&#40;</span><span style="color: #0000ff;">byte</span>*<span class="br0">&#41;</span>ptr;
        <span style="color: #0000ff;">unsafe</span>
        <span class="br0">&#123;</span>
            <span style="color: #808080;">// SAFETY: relies on caller obligation.</span>
            <span style="color: #0000ff;">return</span> addr<span class="br0">&#91;</span>ofs<span class="br0">&#93;</span>;
        <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
    <span style="color: #0000ff;">catch</span> <span class="br0">&#40;</span>NullReferenceException<span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span style="color: #0000ff;">throw</span> <span style="color: #0000ff;">new</span> AccessViolationException<span class="br0">&#40;</span><span class="br0">&#41;</span>;
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></code><hr />
</div><br />
<br />
Le bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #808080;">/// &lt;safety&gt;</span></span> au-dessus de la signature constitue le contrat formel de l'appelant. Le commentaire <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #808080;">// SAFETY:</span></span> à l'intérieur du corps est une note interne indiquant sur quoi repose l'opération non sécurisée.<br />
<br />
La signature seule, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span> <span style="color: #0000ff;">byte</span> ReadByte<span class="br0">&#40;</span>IntPtr, <span style="color: #0000ff;">int</span><span class="br0">&#41;</span></span>, vous indique la forme, mais pas le contrat de sécurité. Le bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #808080;">/// &lt;safety&gt;</span></span> constitue le contrat, c'est pourquoi un analyseur signalera son absence. La leçon à retenir est que connaître la forme d'une API non sécurisée est nécessaire mais pas suffisant pour écrire un code correct. L'écriture de code non sécurisé nécessite des lunettes de sécurité.<br />
<br />
Une seule obligation résiduelle est mentionnée : <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ptr + ofs</span> doit pointer vers un octet lisible. L'appelant doit s'en acquitter. Le mot-clé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> sur la signature est ce qui met en évidence cette obligation pour les appelants. Le commentaire <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #808080;">// SAFETY:</span></span> précise sur quoi repose la déréférence : le fait que l'appelant dispose de garde-fous de sécurité pour cette obligation.<br />
<br />
Considérez les états dans lesquels un paramètre <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">IntPtr</span> peut se trouver lorsqu'un appelant le transmet :<br />
<br />
- <b><span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">IntPtr.Zero</span> (null)</b> : la déréférence se heurte aux pages de protection contre les valeurs nulles du runtime et se traduit par une exception <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">NullReferenceException</span>, que le bloc catch convertit en <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">AccessViolationException</span>. Supprimer le bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">catch</span></span> ne modifierait pas la sécurité, mais uniquement le type d'exception.<br />
<br />
- <b>Un pointeur vers de la mémoire non mappée (non initialisée, libérée ou contenant une valeur aléatoire)</b> : la déréférence provoque une violation d'accès matériel. Sur la plupart des plateformes, cela met fin au processus ; le bloc catch peut même ne pas s'exécuter.<br />
<br />
- <b>Un pointeur vers de la mémoire mappée dont l'appelant n'est pas propriétaire</b> (le tampon de quelqu'un d'autre, le tas du GC, un segment de code) : la déréférence peut réussir. Les pages mappées peuvent tout de même être illisibles (les pages de garde, par exemple), auquel cas le comportement correspond au point précédent. En cas de réussite, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ReadByte</span> renvoie un octet arbitraire de la mémoire avec une valeur arbitraire. Aucune exception, aucun avertissement. Il s'agit là d'un résultat UB classique ; le programme continue en se basant sur des hypothèses corrompues. Dans le pire des cas, il lit de la mémoire qui est interprétée comme une valeur valide pour le programme.<br />
<br />
- <b>Un pointeur dont l'appelant sait avec certitude qu'il pointe vers un octet lisible</b> : fonctionne comme prévu.<br />
<br />
Le try/catch gère le premier cas, échoue de manière non gracieuse dans le deuxième et est invisible dans le troisième. Rien de tout cela n'est de la validation. Le contrat remonte jusqu'à l'appelant, où les informations concernant l'origine, la longueur et la durée de vie du tampon peuvent être utilisées pour exclure les états dangereux. C'est le bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #808080;">/// &lt;safety&gt;</span></span> qui rend ce contrat visible. L'appelant doit comprendre ces cas et s'en prémunir.<br />
<br />
<b><font size="3">Garde de sécurité</font></b><br />
<br />
La documentation énonce les obligations. Les gardes les remplissent. Ce modèle est particulièrement important à la frontière de l'insécurité, là où un développeur atteste que le code non sécurisé a été mis en conformité avec la sécurité fournie par le compilateur. C'est également à cette frontière que la révision doit commencer. Avec une bonne documentation comme guide, le réviseur peut déterminer si le code est conforme.<br />
<br />
On pourrait se demander pourquoi les méthodes non sécurisées n’incluent pas suffisamment de vérifications <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">if</span></span> pour supprimer la nécessité des obligations de l’appelant. Pour <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ReadByte</span>, aucune vérification <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">if</span></span> à l’intérieur de la méthode ne peut valider qu’un <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">IntPtr</span> fourni par l’appelant pointe vers une mémoire lisible : le runtime ne sait tout simplement pas ce que l’appelant a alloué, où, ni pour combien de temps. Les appelants sont les seuls à pouvoir déterminer l’ensemble minimal de vérifications qui maintiennent la sécurité tout en maximisant les performances.<br />
<br />
Remarque : il n’existe pas de nom standard pour ces méthodes/fonctions de frontière. La documentation Rust les appelle « éléments sûrs ». Cet article les appelle « méthodes de frontière non sûres » : des méthodes situées à la frontière entre le code sûr et le code non sûr, où la non-sécurité est supprimée. Le terme « non sûr » est délibéré : ces méthodes conservent toutes les capacités dangereuses des méthodes marquées « unsafe » ; elles ne les propagent simplement pas à leurs appelants.<br />
<br />
<b>Garde de sécurité Rust</b><br />
<br />
Autre exemple en Rust, str.split_at :<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td valign="top"><pre style="margin: 0">pub fn split_at<span class="br0">&#40;</span>&amp;self, mid: usize<span class="br0">&#41;</span> -&gt; <span class="br0">&#40;</span>&amp;str, &amp;str<span class="br0">&#41;</span> <span class="br0">&#123;</span>
    <span style="color: #808080;">// is_char_boundary checks that the index is in [0, .len()]</span>
    <span style="color: #0000ff;">if</span> self.is_char_boundary<span class="br0">&#40;</span>mid<span class="br0">&#41;</span> <span class="br0">&#123;</span>
        <span style="color: #808080;">// SAFETY: just checked that `mid` is on a char boundary.</span>
        <span style="color: #0000ff;">unsafe</span> <span class="br0">&#123;</span> <span class="br0">&#40;</span>self.get_unchecked<span class="br0">&#40;</span><span style="color: #cc66cc;">0</span>..mid<span class="br0">&#41;</span>, self.get_unchecked<span class="br0">&#40;</span>mid..self.len<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> <span class="br0">&#125;</span>
    <span class="br0">&#125;</span> <span style="color: #0000ff;">else</span> <span class="br0">&#123;</span>
        slice_error_fail<span class="br0">&#40;</span>self, <span style="color: #cc66cc;">0</span>, mid<span class="br0">&#41;</span>
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></code><hr />
</div><br />
<br />
Les fonctions de limite non sûres ne comportent généralement que des commentaires <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #808080;">// SAFETY:</span></span> ; elles n’imposent pas d’obligations propres. Le style formel <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #808080;">///</span></span> est réservé aux méthodes <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>, dont la limite se charge alors de remplir les obligations. Les fonctions qui propagent doivent être marquées comme <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>.<br />
<br />
La vérification <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">if</span> self.is_char_boundary<span class="br0">&#40;</span>mid<span class="br0">&#41;</span></span> dans <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">split_at</span> est une garde qui garantit la sécurité du code non sûr qu’elle appelle. Il garantit que la division s'effectue à une limite de caractère, car les caractères Unicode peuvent être multioctets. Si ce test échoue, le programme entre en panique via <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">slice_error_fail</span>. Une panique provoquera le plantage du programme afin d'empêcher tout comportement indéfini.<br />
<br />
Un programme qui entre en panique pour éviter un comportement indéfini est bien plus fiable qu'un programme qui laisse ce comportement se produire.<br />
<br />
<b>Garde de sécurité en C#</b><br />
<br />
Le même modèle de délimitation que dans Rust s'applique en C# : même convention <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #808080;">// SAFETY:</span></span>, même absence de marqueur « unsafe » dans la signature.<br />
<br />
<i>String.CopyTo</i> :<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #808080;">// Converts a substring of this string to an array of characters. Copies the</span>
<span style="color: #808080;">// characters of this string beginning at position sourceIndex and ending at</span>
<span style="color: #808080;">// sourceIndex + count - 1 to the character array buffer, beginning</span>
<span style="color: #808080;">// at destinationIndex.</span>
<span style="color: #808080;">//</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> CopyTo<span class="br0">&#40;</span><span style="color: #0000ff;">int</span> sourceIndex, <span style="color: #0000ff;">char</span><span class="br0">&#91;</span><span class="br0">&#93;</span> destination, <span style="color: #0000ff;">int</span> destinationIndex, <span style="color: #0000ff;">int</span> count<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    ArgumentNullException.ThrowIfNull<span class="br0">&#40;</span>destination<span class="br0">&#41;</span>;
&nbsp;
    ArgumentOutOfRangeException.ThrowIfNegative<span class="br0">&#40;</span>count<span class="br0">&#41;</span>;
    ArgumentOutOfRangeException.ThrowIfNegative<span class="br0">&#40;</span>sourceIndex<span class="br0">&#41;</span>;
    ArgumentOutOfRangeException.ThrowIfGreaterThan<span class="br0">&#40;</span>count, Length - sourceIndex, nameof<span class="br0">&#40;</span>sourceIndex<span class="br0">&#41;</span><span class="br0">&#41;</span>;
    ArgumentOutOfRangeException.ThrowIfGreaterThan<span class="br0">&#40;</span>destinationIndex, destination.Length - count<span class="br0">&#41;</span>;
    ArgumentOutOfRangeException.ThrowIfNegative<span class="br0">&#40;</span>destinationIndex<span class="br0">&#41;</span>;
&nbsp;
    <span style="color: #0000ff;">unsafe</span>
    <span class="br0">&#123;</span>
        <span style="color: #808080;">// SAFETY: the bounds checks above ensure that `count` characters</span>
        <span style="color: #808080;">// starting at `sourceIndex` are in range of this string, and that</span>
        <span style="color: #808080;">// `count` characters starting at `destinationIndex` fit in `destination`.</span>
        Buffer.Memmove<span class="br0">&#40;</span>
            destination: <span style="color: #0000ff;">ref</span> Unsafe.Add<span class="br0">&#40;</span><span style="color: #0000ff;">ref</span> MemoryMarshal.GetArrayDataReference<span class="br0">&#40;</span>destination<span class="br0">&#41;</span>, destinationIndex<span class="br0">&#41;</span>,
            source: <span style="color: #0000ff;">ref</span> Unsafe.Add<span class="br0">&#40;</span><span style="color: #0000ff;">ref</span> _firstChar, sourceIndex<span class="br0">&#41;</span>,
            elementCount: <span class="br0">&#40;</span><span style="color: #0000ff;">uint</span><span class="br0">&#41;</span>count<span class="br0">&#41;</span>;
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></code><hr />
</div><br />
<br />
Chaque appel <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ThrowIf*</span> ici est une mesure de sécurité mémoire. Chacun d'entre eux garantit une invariante que l'appel brut <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Buffer.Memmove</span> suppose :<br />
<br />
- <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ThrowIfNull<span class="br0">&#40;</span>destination<span class="br0">&#41;</span></span> : sans cela, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">MemoryMarshal.GetArrayDataReference<span class="br0">&#40;</span><span style="color: #0000ff;">null</span><span class="br0">&#41;</span></span> est UB.<br />
<br />
- <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ThrowIfNegative<span class="br0">&#40;</span>count<span class="br0">&#41;</span></span> : sans cela, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span class="br0">&#40;</span><span style="color: #0000ff;">uint</span><span class="br0">&#41;</span>count</span> convertit silencieusement une valeur négative en un <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">elementCount</span> énorme, et la copie hors limites qui en résulte est UB.<br />
<br />
- <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ThrowIfNegative<span class="br0">&#40;</span>sourceIndex<span class="br0">&#41;</span></span> et <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ThrowIfNegative<span class="br0">&#40;</span>destinationIndex<span class="br0">&#41;</span></span> : sans elles, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Unsafe.Add<span class="br0">&#40;</span><span style="color: #0000ff;">ref</span> &#133;, negativeIndex<span class="br0">&#41;</span></span> fait sortir la référence de la zone de stockage, et la lecture ou l'écriture qui en résulte est UB.<br />
<br />
- Les deux vérifications <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ThrowIfGreaterThan</span> s’ajoutent aux vérifications négatives ci-dessus (et s’appuient sur l’invariance d’exécution selon laquelle <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Length</span> est dans <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span class="br0">&#91;</span><span style="color: #cc66cc;">0</span>, <span style="color: #0000ff;">int</span>.MaxValue<span class="br0">&#93;</span></span>, de sorte que <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Length - sourceIndex</span> ne déborde pas) pour limiter count par rapport à la capacité restante de source et de destination. Sans elles, la copie peut dépasser la fin de l’un ou l’autre des tampons, et la lecture ou l’écriture qui en résulte est UB.<br />
<br />
Les vérifications s’enchaînent. Chacune n’est suffisante que parce que les précédentes ont déjà écarté certaines classes d’entrées. Modifiez n’importe quel maillon de cette chaîne (passez à un type d’index non signé, ou modifiez ce que le runtime garantit concernant <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Length</span>), et le raisonnement de sécurité doit être redéfini.<br />
<br />
Les méthodes <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ThrowIf*</span> sont l'équivalent en C# des aides à la panique de Rust telles que <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">slice_error_fail</span> ; toutes deux provoquent le plantage du programme à la limite plutôt que de laisser un comportement indéfini se produire, et toutes deux sont factorisées en fonctions distinctes afin de maintenir les chemins froids hors du code chaud.<br />
<br />
<b><font size="3">Champs unsafe</font></b><br />
<br />
Les champs méritent une discussion. Un champ doit être <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Unsafe</span> lorsque son type déclaré n'exprime pas une invariante que le type englobant maintient et dont le code en aval dépend. La non-sécurité réside dans l'écart entre ce que le système de types voit et ce que le type englobant promet.<br />
<br />
Le cas le plus simple est un champ contenant un pointeur natif. L'exemple ci-dessous est une maquette ; il ne provient pas de dotnet/runtime comme les autres exemples.<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> NativeBuffer : IDisposable
<span class="br0">&#123;</span>
    <span style="color: #808080;">/// &lt;safety&gt;</span>
    <span style="color: #808080;">/// Must be null or point to a buffer of Length bytes.</span>
    <span style="color: #808080;">/// &lt;/safety&gt;</span>
    <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">unsafe</span> <span style="color: #0000ff;">byte</span>* _ptr;
    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">int</span> Length <span class="br0">&#123;</span> <span style="color: #0000ff;">get</span>; <span class="br0">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">public</span> NativeBuffer<span class="br0">&#40;</span><span style="color: #0000ff;">int</span> length<span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        ArgumentOutOfRangeException.ThrowIfNegative<span class="br0">&#40;</span>length<span class="br0">&#41;</span>;
        <span style="color: #0000ff;">unsafe</span>
        <span class="br0">&#123;</span>
            <span style="color: #808080;">// SAFETY: NativeMemory.Alloc throws OutOfMemoryException on failure rather than</span>
            <span style="color: #808080;">// returning null (unlike the malloc it wraps), so on return _ptr points to `length` bytes.</span>
            _ptr = <span class="br0">&#40;</span><span style="color: #0000ff;">byte</span>*<span class="br0">&#41;</span>NativeMemory.Alloc<span class="br0">&#40;</span><span class="br0">&#40;</span>nuint<span class="br0">&#41;</span>length<span class="br0">&#41;</span>;
        <span class="br0">&#125;</span>
        Length = length;
    <span class="br0">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">byte</span> ReadAt<span class="br0">&#40;</span><span style="color: #0000ff;">int</span> index<span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        ArgumentOutOfRangeException.ThrowIfNegative<span class="br0">&#40;</span>index<span class="br0">&#41;</span>;
        ArgumentOutOfRangeException.ThrowIfGreaterThanOrEqual<span class="br0">&#40;</span>index, Length<span class="br0">&#41;</span>;
        <span style="color: #0000ff;">unsafe</span>
        <span class="br0">&#123;</span>
            ObjectDisposedException.ThrowIf<span class="br0">&#40;</span>_ptr <span style="color: #0000ff;">is</span> <span style="color: #0000ff;">null</span>, <span style="color: #0000ff;">this</span><span class="br0">&#41;</span>;
            <span style="color: #808080;">// SAFETY: bounds checked above; null check just above; _ptr therefore points to Length bytes</span>
            <span style="color: #0000ff;">return</span> _ptr<span class="br0">&#91;</span>index<span class="br0">&#93;</span>;
        <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span> Dispose<span class="br0">&#40;</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span style="color: #0000ff;">unsafe</span>
        <span class="br0">&#123;</span>
            <span style="color: #808080;">// SAFETY: _ptr is null or was returned by NativeMemory.Alloc; Free accepts both</span>
            NativeMemory.Free<span class="br0">&#40;</span>_ptr<span class="br0">&#41;</span>;
            _ptr = <span style="color: #0000ff;">null</span>;
        <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></code><hr />
</div>La classe est sûre à l'appel, le champ <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> portant l'invariant de validité au nom de l'interface publique. <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Length</span> est une propriété automatique en lecture seule fixée lors de la construction ; son immuabilité constitue l'autre moitié de l'invariant, puisque l'obligation de taille de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">_ptr</span> est exprimée en termes de Length. Si <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Length</span> pouvait changer après la construction, il faudrait un marqueur <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> et un bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">&lt;safety&gt;</span> spécifiques pour maintenir la cohérence du couple. <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Dispose</span> affaiblit délibérément cet invariant de « valide » à « null ou valide » en écrivant <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">null</span>, ce qui explique pourquoi <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">_ptr</span> ne peut pas être en lecture seule <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">readonly</span></span> et pourquoi <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ReadAt</span> vérifie la présence de null avant la déréférence. Le marqueur <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> sur le champ permet de garder les deux écritures (l'allocation dans le constructeur et l'invalidation dans <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Dispose</span>) vérifiables en un seul endroit.<br />
<br />
Un cas plus courant dans les bibliothèques d'exécution est celui d'un champ dont le type déclaré est correct mais moins spécifique que ce que la classe gère réellement. Le document de conception donne une version simplifiée de ce modèle : une classe générique contient un champ <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Array</span> qui doit toujours contenir un <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">T<span class="br0">&#91;</span><span class="br0">&#93;</span></span>. <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Array</span> est l'objet des types de tableaux ; chaque <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">T<span class="br0">&#91;</span><span class="br0">&#93;</span></span> est un <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Array</span>, donc déclarer le champ comme <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Array</span> est correct du point de vue du type, et cela évite les coûts de spécialisation générique. Le système de types C# permet d'affecter n'importe quel tableau à ce champ, alors que la classe garantit toujours exactement <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">T<span class="br0">&#91;</span><span class="br0">&#93;</span></span>. Le risque réside dans cet écart : le système de types ne peut pas voir l'invariant plus strict, et la classe est chargée de le respecter.<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> ArrayWrapper&lt;T&gt;
<span class="br0">&#123;</span>
    <span style="color: #808080;">/// &lt;safety&gt;</span>
    <span style="color: #808080;">/// Must always hold a value whose runtime type is T[].</span>
    <span style="color: #808080;">/// &lt;/safety&gt;</span>
    <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">readonly</span> <span style="color: #0000ff;">unsafe</span> Array _array;
&nbsp;
    <span style="color: #0000ff;">public</span> ArrayWrapper<span class="br0">&#40;</span>T<span class="br0">&#91;</span><span class="br0">&#93;</span> items<span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        ArgumentNullException.ThrowIfNull<span class="br0">&#40;</span>items<span class="br0">&#41;</span>;
        <span style="color: #0000ff;">unsafe</span>
        <span class="br0">&#123;</span>
            <span style="color: #808080;">// SAFETY: items is statically T[], so the field invariant holds.</span>
            _array = items;
        <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">public</span> T GetItem<span class="br0">&#40;</span><span style="color: #0000ff;">int</span> index<span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span style="color: #0000ff;">unsafe</span>
        <span class="br0">&#123;</span>
            <span style="color: #808080;">// SAFETY: _array is always a T[] per the field's &lt;safety&gt; block</span>
            <span style="color: #0000ff;">var</span> typedArray = Unsafe.As&lt;T<span class="br0">&#91;</span><span class="br0">&#93;</span>&gt;<span class="br0">&#40;</span>_array<span class="br0">&#41;</span>;
            <span style="color: #0000ff;">return</span> typedArray<span class="br0">&#91;</span>index<span class="br0">&#93;</span>;
        <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></code><hr />
</div><br />
<br />
Le modèle est le même que celui de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">NativeBuffer</span> : un champ <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> avec un invariant documenté, des blocs non sécurisés à la limite qui le libèrent, et une interface publique pouvant être appelée en toute sécurité.<br />
<br />
Rust travaille sur le même problème, et la proposition relative aux champs non sécurisés utilise <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Vec&lt;T&gt;</span> comme cas d'étude. <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Vec&lt;T&gt;</span> comporte une invariante selon laquelle les éléments à <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">data<span class="br0">&#91;</span>i<span class="br0">&#93;</span></span> pour <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">i &lt; len</span> sont initialisés. Aujourd'hui, cette invariante n'existe que dans les commentaires et la documentation. Rien n'empêche une méthode (même privée) de désynchroniser <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">len</span> et <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">data</span> dans un code entièrement sûr :<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br /></div></td><td valign="top"><pre style="margin: 0">pub <span style="color: #0000ff;">struct</span> Vec&lt;T&gt; <span class="br0">&#123;</span>
    data: Box&lt;<span class="br0">&#91;</span>MaybeUninit&lt;T&gt;<span class="br0">&#93;</span>&gt;,
    len: usize,
<span class="br0">&#125;</span>
&nbsp;
impl&lt;T&gt; Vec&lt;T&gt; <span class="br0">&#123;</span>
    <span style="color: #808080;">// Safe code, but the next read is undefined behavior.</span>
    pub fn evil<span class="br0">&#40;</span>&amp;mut self<span class="br0">&#41;</span> <span class="br0">&#123;</span>
        self.len += <span style="color: #cc66cc;">2</span>;
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></code><hr />
</div><br />
<br />
La forme proposée pour l'avenir intègre l'invariance dans le système de types en marquant les deux champs comme non sécurisés :<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">struct</span> Vec&lt;T&gt; <span class="br0">&#123;</span>
    <span style="color: #808080;">// SAFETY: The elements `data[i]` for</span>
    <span style="color: #808080;">// `i &lt; len` are in a valid state.</span>
    <span style="color: #0000ff;">unsafe</span> data: Box&lt;<span class="br0">&#91;</span>MaybeUninit&lt;T&gt;<span class="br0">&#93;</span>&gt;,
    <span style="color: #0000ff;">unsafe</span> len: usize,
<span class="br0">&#125;</span></pre></td></tr></table></code><hr />
</div><br />
<br />
Avec ce changement, toute écriture sur <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">len</span> ou <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">data</span> doit désormais s'effectuer à l'intérieur d'un bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> ; <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">evil</span> ne se compile plus tel quel. Les deux champs sont vérifiés ensemble, au même endroit, par rapport au même contrat. C'est exactement le même avantage dont bénéficie <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">NativeBuffer</span> en associant un pointeur <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span> de type <span style="color: #0000ff;">byte</span>* _ptr</span> à une longueur fixe, et dont bénéficie <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ArrayWrapper&lt;T&gt;</span> en associant <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">readonly</span> <span style="color: #0000ff;">unsafe</span> Array _array</span> à la promesse toujours de type <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">T<span class="br0">&#91;</span><span class="br0">&#93;</span></span>.<br />
<br />
Vous pourriez dire que l'on peut toujours écrire <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">evil</span> avec <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> et que cela aboutit toujours à un comportement indéfini (UB). Oui. L'idée générale est que le code unsafe est marqué et facile à auditer. C'est le fondement de la sécurité dans tous ces langages.<br />
<br />
Quelques règles empiriques pour l’utilisation de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> sur les champs :<br />
<br />
- <b>Les écritures constituent la motivation principale.</b> L’utilisation de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> sur le champ force chaque écriture dans un contexte vérifiable où le contrat est visible, établissant (au moins) la discipline entre membres qui préserve l’invariant. Par exemple, une écriture sur <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">_ptr</span> dans l’exemple <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">NativeBuffer</span> violerait <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Length</span>.<br />
<br />
- <b>Les champs readonly répondent en grande partie au même besoin.</b> Il est utile de considérer <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span> <span style="color: #0000ff;">readonly</span></span> comme le contrat plus une protection intégrée : <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> nomme l’invariant, et <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">readonly</span></span> est la protection de sécurité qui empêche les écritures post-construction de le violer. Supprimez <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">readonly</span></span> et le contrat reste en place ; il doit simplement être respecté de la manière la plus difficile, en vérifiant chaque site d'écriture. L'exemple <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ArrayWrapper&lt;T&gt;</span> ci-dessus est <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">readonly</span> <span style="color: #0000ff;">unsafe</span></span> précisément pour cette raison. Rust converge vers la même forme via les axiomes de conception des champs unsafe : le marqueur reste, mais les opérations qu'il contrôle (écritures, réinitialisation) sont exactement celles que l'immuabilité empêche déjà.<br />
<br />
- <b>Private n'est pas un passe-droit.</b> Il est tentant de supposer que, puisqu’un champ est privé, on peut faire confiance aux méthodes propres au type pour maintenir l’invariance. C’était l’ancien modèle de type <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>. Dans le nouveau modèle, l’interaction entre membres est elle-même une surface de contrat ; l’écriture correcte d’une méthode peut être annulée par l’écriture non coordonnée d’une autre méthode. La non-sécurité consiste à protéger le contrat contre tout code susceptible de le violer, y compris le code au sein du type lui-même.<br />
<br />
<b><font size="3">Guide de migration</font></b><br />
<br />
La meilleure façon de comprendre le modèle est de migrer du code existant vers celui-ci. C’est ce que fait l’équipe .NET à travers les bibliothèques d’exécution. Choisissez une API <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>, suivez-la jusqu’à un appelant, et déterminez si la migration peut décharger les obligations de l’appelé en ligne ou si elle doit les propager vers le haut. Chaque appelant est un emplacement candidat pour la limite ; la migration permet de déterminer si c’est là que la limite doit se situer.<br />
<br />
Cette section est spéculative. Le modèle n’est pas finalisé et les bibliothèques d’exécution n’ont pas encore été migrées. Les exemples sont des hypothèses éclairées, destinées à montrer où nous allons et ce que le nouveau modèle implique pour le code existant.<br />
<br />
Nous allons migrer dans cette section certaines méthodes qui aboutissent à <i>NativeMemory.Alloc</i> et <i>NativeMemory.Free</i>. Voici à quoi ressemblent les deux méthodes <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">NativeMemory</span> dans le nouveau modèle :<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">void</span>* Alloc<span class="br0">&#40;</span>nuint byteCount<span class="br0">&#41;</span>;
&nbsp;
<span style="color: #808080;">/// &lt;safety&gt;</span>
<span style="color: #808080;">/// The caller must ensure:</span>
<span style="color: #808080;">///</span>
<span style="color: #808080;">/// - &lt;paramref name=&quot;ptr&quot;/&gt; was returned by &lt;see cref=&quot;Alloc(nuint)&quot;/&gt; (or a</span>
<span style="color: #808080;">///   compatible allocator) and has not already been freed.</span>
<span style="color: #808080;">/// - No live pointer or span aliases the storage at the time of this call.</span>
<span style="color: #808080;">/// &lt;/safety&gt;</span>
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">unsafe</span> <span style="color: #0000ff;">void</span> Free<span class="br0">&#40;</span><span style="color: #0000ff;">void</span>* ptr<span class="br0">&#41;</span>;</pre></td></tr></table></code><hr />
</div><br />
<br />
L'asymétrie est intentionnelle. <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Alloc</span> devient sûr. Il renvoie un <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">void</span>*</span>, mais le fait de détenir un pointeur n'est pas dangereux en soi ; le danger réside dans la déréférence finale, que l'appelant encapsule. Ne pas libérer la mémoire entraîne une fuite, pas un problème de sécurité. (<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Alloc</span> diffère également de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">malloc</span> en ce qu'il lève une exception <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">OutOfMemoryException</span> en cas d'échec plutôt que de renvoyer null, de sorte que les appelants n'ont pas à vérifier la valeur renvoyée.) <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Free</span> reste dangereux car il comporte de véritables conditions préalables : le pointeur doit être celui renvoyé par un allocateur compatible et ne pas avoir déjà été libéré, et rien d’autre ne peut être un alias de la mémoire. Le bloc &lt;safety&gt; rend ces obligations visibles pour tous les appelants et réviseurs.<br />
<br />
Passons maintenant à un appelant. Voici une maquette du constructeur de <i>FileVersionInfo</i> sous le nouveau modèle. Le constructeur analyse un blob d'informations de version natif pour le convertir en champs de type chaîne et entier de cet objet (<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">_companyName</span>, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">_fileVersion</span>, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">_fileMajor</span>, etc.) ; l'allocation correspond simplement au tampon temporaire qui contient le blob pendant que <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">GetVersionInfoForCodePage</span> le lit.<br />
<br />
Signature actuelle : <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">private</span> <span style="color: #0000ff;">unsafe</span> FileVersionInfo<span class="br0">&#40;</span><span style="color: #0000ff;">string</span> fileName<span class="br0">&#41;</span></span>. Elle est <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> uniquement pour établir un contexte non sécurisé.<br />
<br />
Voici la signature et l'implémentation mises à jour, accompagnées de commentaires internes sur la sécurité.<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">private</span> FileVersionInfo<span class="br0">&#40;</span><span style="color: #0000ff;">string</span> fileName<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    _fileName = fileName;
&nbsp;
    <span style="color: #0000ff;">uint</span> infoSize = Interop.Version.GetFileVersionInfoSizeEx<span class="br0">&#40;</span>
        Interop.Version.FileVersionInfoType.FILE_VER_GET_LOCALISED, _fileName, <span style="color: #0000ff;">out</span> _<span class="br0">&#41;</span>;
    <span style="color: #0000ff;">if</span> <span class="br0">&#40;</span>infoSize != <span style="color: #cc66cc;">0</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span style="color: #0000ff;">unsafe</span>
        <span class="br0">&#123;</span>
            <span style="color: #808080;">// SAFETY:</span>
            <span style="color: #808080;">// - bounds: `infoSize` is the size returned by GetFileVersionInfoSizeEx</span>
            <span style="color: #808080;">//   and is the same value passed to both Alloc and GetFileVersionInfoEx,</span>
            <span style="color: #808080;">//   so all reads through `memPtr` stay within the allocated range.</span>
            <span style="color: #808080;">// - lifetime: `memPtr` is freed in the finally before this constructor</span>
            <span style="color: #808080;">//   returns, and never escapes; every consumer (GetLanguageAndCodePage,</span>
            <span style="color: #808080;">//   GetVersionInfoForCodePage) is called from within this method and</span>
            <span style="color: #808080;">//   writes its results into this object's fields.</span>
            <span style="color: #0000ff;">void</span>* memPtr = NativeMemory.Alloc<span class="br0">&#40;</span>infoSize<span class="br0">&#41;</span>;
            <span style="color: #0000ff;">try</span>
            <span class="br0">&#123;</span>
                <span style="color: #0000ff;">if</span> <span class="br0">&#40;</span>Interop.Version.GetFileVersionInfoEx<span class="br0">&#40;</span>
                    <span style="color: #808080;">/* flags */</span> <span style="color: #0000ff;">default</span>, _fileName, <span style="color: #cc66cc;">0</span>U, infoSize, memPtr<span class="br0">&#41;</span><span class="br0">&#41;</span>
                <span class="br0">&#123;</span>
                    <span style="color: #0000ff;">uint</span> lcp = GetLanguageAndCodePage<span class="br0">&#40;</span>memPtr<span class="br0">&#41;</span>;
                    _ = GetVersionInfoForCodePage<span class="br0">&#40;</span>memPtr, lcp.ToString<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;X8&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> ||
                        <span class="br0">&#40;</span>lcp != <span style="color: #cc66cc;">0x040904B0</span> &amp;&amp; GetVersionInfoForCodePage<span class="br0">&#40;</span>memPtr, <span style="color: #FF0000;">&quot;040904B0&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> ||
                        <span class="br0">&#40;</span>lcp != <span style="color: #cc66cc;">0x040904E4</span> &amp;&amp; GetVersionInfoForCodePage<span class="br0">&#40;</span>memPtr, <span style="color: #FF0000;">&quot;040904E4&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span> ||
                        <span class="br0">&#40;</span>lcp != <span style="color: #cc66cc;">0x04090000</span> &amp;&amp; GetVersionInfoForCodePage<span class="br0">&#40;</span>memPtr, <span style="color: #FF0000;">&quot;04090000&quot;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>;
                <span class="br0">&#125;</span>
            <span class="br0">&#125;</span>
            <span style="color: #0000ff;">finally</span>
            <span class="br0">&#123;</span>
                NativeMemory.Free<span class="br0">&#40;</span>memPtr<span class="br0">&#41;</span>;
            <span class="br0">&#125;</span>
        <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></code><hr />
</div><br />
<br />
Le constructeur constitue une limite de sécurité solide. Les autres risques de sécurité (les appels d'interopérabilité qui lisent via <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">memPtr</span> et l'appel à <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Free</span> à la fin) sont gérés en ligne :<br />
<br />
- <b>Limites</b> : une seule valeur <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">infoSize</span> est transmise depuis l'appel de requête de taille vers <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Alloc</span> et vers chaque appel d'interopérabilité qui lit via <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">memPtr</span> ; les trois utilisations sont liées entre elles par leur nom, de sorte que les lectures restent dans la plage allouée.<br />
<br />
- <b>Durée de vie</b> : le bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">try</span>/<span style="color: #0000ff;">finally</span></span> garantit que <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Free</span> s'exécute avant que le constructeur ne renvoie une valeur, même en cas d'exception provenant des appels d'interopérabilité. Le pointeur ne s'échappe jamais ; chaque aide qui l'utilise est appelée à l'intérieur de cette méthode, donc aucun alias ne survit au-delà de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Free</span>.<br />
<br />
Pas de marqueur <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> sur le constructeur, pas de bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">&lt;safety&gt;</span> ; l'insécurité est entièrement confinée à l'intérieur du corps. Les constructeurs unsafe sont possibles dans le nouveau modèle (ils propagent l'obligation vers tout code qui instancie le type), mais celui-ci n'a pas besoin d'être unsafe.<br />
<br />
Voici maintenant une maquette de <i>FixedMemoryKeyBox</i> :<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br />33<br />34<br />35<br />36<br />37<br />38<br />39<br />40<br />41<br />42<br />43<br />44<br />45<br />46<br />47<br />48<br />49<br />50<br />51<br />52<br />53<br />54<br />55<br />56<br />57<br />58<br />59<br />60<br />61<br />62<br />63<br />64<br />65<br />66<br />67<br />68<br />69<br />70<br />71<br />72<br />73<br />74<br />75<br />76<br />77<br />78<br />79<br />80<br />81<br />82<br />83<br />84<br />85<br />86<br />87<br />88<br />89<br /></div></td><td valign="top"><pre style="margin: 0"><span style="color: #0000ff;">internal</span> <span style="color: #0000ff;">sealed</span> <span style="color: #0000ff;">class</span> FixedMemoryKeyBox : SafeHandle
<span class="br0">&#123;</span>
    <span style="color: #808080;">/// &lt;safety&gt;</span>
    <span style="color: #808080;">/// Must equal the byte size of the allocation pointed to by &lt;c&gt;handle&lt;/c&gt;.</span>
    <span style="color: #808080;">/// &lt;/safety&gt;</span>
    <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">readonly</span> <span style="color: #0000ff;">unsafe</span> <span style="color: #0000ff;">int</span> _length;
&nbsp;
    <span style="color: #0000ff;">internal</span> FixedMemoryKeyBox<span class="br0">&#40;</span>ReadOnlySpan&lt;<span style="color: #0000ff;">byte</span>&gt; key<span class="br0">&#41;</span> : <span style="color: #0000ff;">base</span><span class="br0">&#40;</span>IntPtr.Zero, ownsHandle: <span style="color: #0000ff;">true</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span style="color: #0000ff;">void</span>* memory;
        <span style="color: #0000ff;">unsafe</span>
        <span class="br0">&#123;</span>
            <span style="color: #808080;">// SAFETY:</span>
            <span style="color: #808080;">// - alloc:   NativeMemory.Alloc returns a pointer to key.Length writable bytes.</span>
            <span style="color: #808080;">// - span:    new Span&lt;byte&gt;(memory, key.Length) addresses exactly those bytes.</span>
            <span style="color: #808080;">// - lifetime: ownership of the pointer transfers to this SafeHandle</span>
            <span style="color: #808080;">//             via SetHandle below; ReleaseHandle frees the allocation when</span>
            <span style="color: #808080;">//             the ref-count reaches zero.</span>
            <span style="color: #808080;">// - _length: paired with the allocation made on this line.</span>
            memory = NativeMemory.Alloc<span class="br0">&#40;</span><span class="br0">&#40;</span>nuint<span class="br0">&#41;</span>key.Length<span class="br0">&#41;</span>;
            key.CopyTo<span class="br0">&#40;</span><span style="color: #0000ff;">new</span> Span&lt;<span style="color: #0000ff;">byte</span>&gt;<span class="br0">&#40;</span>memory, key.Length<span class="br0">&#41;</span><span class="br0">&#41;</span>;
            _length = key.Length;
        <span class="br0">&#125;</span>
        SetHandle<span class="br0">&#40;</span><span class="br0">&#40;</span>IntPtr<span class="br0">&#41;</span>memory<span class="br0">&#41;</span>;
    <span class="br0">&#125;</span>
&nbsp;
    <span style="color: #808080;">/// &lt;safety&gt;</span>
    <span style="color: #808080;">/// The returned span aliases storage owned by this SafeHandle.</span>
    <span style="color: #808080;">/// The caller must ensure:</span>
    <span style="color: #808080;">///</span>
    <span style="color: #808080;">/// - the span is not used after this SafeHandle is disposed;</span>
    <span style="color: #808080;">/// - access is bracketed by &lt;see cref=&quot;SafeHandle.DangerousAddRef&quot;/&gt; and</span>
    <span style="color: #808080;">///   &lt;see cref=&quot;SafeHandle.DangerousRelease&quot;/&gt; (or equivalent), so</span>
    <span style="color: #808080;">///   disposal on another thread can't free the buffer mid-use.</span>
    <span style="color: #808080;">/// &lt;/safety&gt;</span>
    <span style="color: #0000ff;">internal</span> <span style="color: #0000ff;">unsafe</span> ReadOnlySpan&lt;<span style="color: #0000ff;">byte</span>&gt; DangerousKeySpan
    <span class="br0">&#123;</span>
        <span style="color: #0000ff;">get</span>
        <span class="br0">&#123;</span>
            <span style="color: #0000ff;">unsafe</span>
            <span class="br0">&#123;</span>
                <span style="color: #808080;">// SAFETY:</span>
                <span style="color: #808080;">// - bounds: `_length` matches the allocation made in the ctor.</span>
                <span style="color: #808080;">// - lifetime: NOT discharged here; propagated to the caller</span>
                <span style="color: #808080;">//   via the &lt;safety&gt; block above. The `Dangerous` prefix</span>
                <span style="color: #808080;">//   echoes that contract in the API name.</span>
                <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">new</span> ReadOnlySpan&lt;<span style="color: #0000ff;">byte</span>&gt;<span class="br0">&#40;</span><span class="br0">&#40;</span><span style="color: #0000ff;">void</span>*<span class="br0">&#41;</span>handle, _length<span class="br0">&#41;</span>;
            <span class="br0">&#125;</span>
        <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">internal</span> TRet UseKey&lt;TState, TRet&gt;<span class="br0">&#40;</span>TState state, Func&lt;TState, ReadOnlySpan&lt;<span style="color: #0000ff;">byte</span>&gt;, TRet&gt; func<span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span style="color: #0000ff;">bool</span> addedRef = <span style="color: #0000ff;">false</span>;
        <span style="color: #0000ff;">unsafe</span>
        <span class="br0">&#123;</span>
            <span style="color: #808080;">// SAFETY: AddRef holds the SafeHandle alive for the duration of</span>
            <span style="color: #808080;">// the callback, so `DangerousKeySpan` aliases live storage. The</span>
            <span style="color: #808080;">// span is not retained beyond `func`'s return.</span>
            <span style="color: #0000ff;">try</span>
            <span class="br0">&#123;</span>
                DangerousAddRef<span class="br0">&#40;</span><span style="color: #0000ff;">ref</span> addedRef<span class="br0">&#41;</span>;
                <span style="color: #0000ff;">return</span> func<span class="br0">&#40;</span>state, DangerousKeySpan<span class="br0">&#41;</span>;
            <span class="br0">&#125;</span>
            <span style="color: #0000ff;">finally</span>
            <span class="br0">&#123;</span>
                <span style="color: #0000ff;">if</span> <span class="br0">&#40;</span>addedRef<span class="br0">&#41;</span>
                <span class="br0">&#123;</span>
                    DangerousRelease<span class="br0">&#40;</span><span class="br0">&#41;</span>;
                <span class="br0">&#125;</span>
            <span class="br0">&#125;</span>
        <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">protected</span> <span style="color: #0000ff;">override</span> <span style="color: #0000ff;">bool</span> ReleaseHandle<span class="br0">&#40;</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span style="color: #0000ff;">unsafe</span>
        <span class="br0">&#123;</span>
            <span style="color: #808080;">// SAFETY: SafeHandle's ref-counting guarantees no live span</span>
            <span style="color: #808080;">// aliases `handle` at this point; the new Span&lt;byte&gt;(handle, _length)</span>
            <span style="color: #808080;">// addresses the allocation made in the ctor.</span>
            CryptographicOperations.ZeroMemory<span class="br0">&#40;</span><span style="color: #0000ff;">new</span> Span&lt;<span style="color: #0000ff;">byte</span>&gt;<span class="br0">&#40;</span><span class="br0">&#40;</span><span style="color: #0000ff;">void</span>*<span class="br0">&#41;</span>handle, _length<span class="br0">&#41;</span><span class="br0">&#41;</span>;
            NativeMemory.Free<span class="br0">&#40;</span><span class="br0">&#40;</span><span style="color: #0000ff;">void</span>*<span class="br0">&#41;</span>handle<span class="br0">&#41;</span>;
        <span class="br0">&#125;</span>
        <span style="color: #0000ff;">return</span> <span style="color: #0000ff;">true</span>;
    <span class="br0">&#125;</span>
&nbsp;
    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">override</span> <span style="color: #0000ff;">bool</span> IsInvalid =&gt; handle == IntPtr.Zero;
<span class="br0">&#125;</span></pre></td></tr></table></code><hr />
</div><br />
<br />
<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">FixedMemoryKeyBox</span> regroupe deux limites dans un seul type, illustrant les deux sens :<br />
<br />
- <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">DangerousKeySpan</span> est un appelant <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>. Bounds est libéré en ligne par l'invariance du champ <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">_length</span>. L' <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">int</span></span> est sûr en soi ; le problème de sécurité réside dans son couplage avec <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">handle</span> : ils forment une paire qui doit correspondre. La durée de vie n'est pas gérée. Le span fait référence à la mémoire détenue par le SafeHandle, et cette mémoire survit à l'appel de la propriété par conception. Le bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">&lt;safety&gt;</span> énonce deux obligations résiduelles : ne pas survivre au SafeHandle, et encadrer l'accès avec <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">DangerousAddRef</span>/<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Release</span>. Le compilateur ne peut imposer aucune de ces deux obligations. Le marqueur indique aux appelants qu'ils ont du travail à faire.<br />
<br />
- <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">UseKey</span> est la limite de sécurité construite par-dessus. Elle remplit l'obligation de durée de vie en encadrant le rappel avec <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">DangerousAddRef</span>/<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Release</span> dans un <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">try</span>/<span style="color: #0000ff;">finally</span></span>. Le <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ReadOnlySpan&lt;<span style="color: #0000ff;">byte</span>&gt;</span> passé à <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">func</span> est sûr en vertu des règles de durée de vie des <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">ref</span> <span style="color: #0000ff;">struct</span></span>. De l'extérieur, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">UseKey</span> est sûr à appeler ; l'insécurité est scellée à l'intérieur de l'encadrement.<br />
<br />
<b><font size="3">Distribution binaire</font></b><br />
<br />
Les bibliothèques .NET sont souvent distribuées sous forme de binaires. Une bibliothèque populaire publiée sur nuget.org peut comporter zéro ou mille avertissements, mais vous savez qu’elle ne contient aucune erreur. Les erreurs sont l’un des rares aspects de la compilation qui sont communiqués de manière fiable entre le producteur et le consommateur.<br />
<br />
Le mode <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> de C# 16 s’appuie fortement sur les nouvelles erreurs de compilation. Opter pour le nouveau modèle signifie que le travail d’annotation a été effectué. Il sera simple d’inspecter un projet et de voir s’il utilise du code <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>.<br />
<br />
Swift, par exemple, s'appuie davantage sur les avertissements pour l'adoption de la sécurité mémoire. La charge de travail pour Swift est bien moindre puisque les dépendances sont distribuées sous forme de code source. Vous pouvez voir les erreurs et les avertissements des dépendances avec la même précision lors de la compilation. Rust dispose également de dépendances distribuées sous forme de code source, mais s'appuie fortement sur les erreurs.<br />
<br />
Nous envisageons d'ajouter des badges sur nuget.org pour encourager l'adoption de la nouvelle mise en œuvre de la sécurité de la mémoire et pour faciliter la recherche des bibliothèques qui l'ont adoptée. Les bibliothèques et les paquets ayant adopté le modèle seront marqués en conséquence, ce qui facilitera l'inspection et la compréhension de l'état de sécurité de votre chaîne d'approvisionnement (tel que le compilateur le perçoit).<br />
<br />
Il sera courant que des projets compilés avec l'ancien modèle utilisent des paquets construits avec le nouveau, et vice versa. Comme décrit dans la section « En bref », les deux sens sont asymétriques. Un projet ayant opté pour le nouveau modèle applique les règles du mode compat aux paquets hérités : tout type de pointeur dans une signature d’appelé nécessite un bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span> <span class="br0">&#123;</span> <span class="br0">&#125;</span></span> englobant au site d’appel. Un projet hérité, en revanche, considère les paquets ayant opté pour le nouveau modèle comme des assemblages ordinaires et n’est soumis à aucun nouveau diagnostic. Cette asymétrie est délibérée. Le côté ayant opté pour le nouveau modèle apporte la garantie de sécurité, et le mode compat empêche cette garantie de se dégrader silencieusement lors de l’utilisation de code hérité.<br />
<br />
<b><font size="3">Espace de conception restant</font></b><br />
<br />
L'intention de notre projet est de déployer tous les aspects du nouveau modèle en une seule fois, à la fois parce qu'il n'est cohérent qu'en tant qu'ensemble, et pour éviter aux développeurs d'avoir à adopter une série progressive de changements rompant la compatibilité. Cependant, il existe quelques aspects de conception que nous n'avons pas pu traiter dans C# 16.<br />
<br />
Le premier est la réflexion, qui constitue une exception dans le modèle. Le code peut appeler des API <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> via <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">MethodInfo.Invoke</span> sans bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> englobant, et les écritures de réflexion peuvent enfreindre les invariants documentés sur les champs <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>. Le code faisant un usage intensif de la réflexion doit être examiné pour détecter les appels d'API non sécurisés et les écritures qui contournent les contrats exprimés par le nouveau modèle. Nous aborderons peut-être l'utilisation de la réflexion dans une version ultérieure.<br />
<br />
Le deuxième point concerne les durées de vie. Rust gère les durées de vie via son vérificateur d’emprunt ; nous n’envisageons pas de mettre en place un système omniprésent comme celui des emprunts. C# s’appuie sur un ramasse-miettes et un système de propriété basé sur les références pour couvrir en partie le même domaine. Nous envisageons un modèle de propriété ciblé, comme mentionné dans la section « Sécurité de la mémoire dans .NET ». Nous publierons ultérieurement des plans de conception à ce sujet.<br />
<br />
Le principal cas d'utilisation d'une application plus stricte des durées de vie est ArrayPool, en particulier pour les méthodes <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Rent</span> et <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Return</span>. Le scénario clé consiste à renvoyer un tableau et à continuer de l'utiliser. Il s'agit d'une violation de type « utilisation après libération ». Il est facile de se tromper sur la convention, et nous avons commis cette erreur dans notre propre code. En revanche, une utilisation de <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Rent</span> sans <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Return</span> constitue une fuite et non une violation de la sécurité de la mémoire.<br />
<br />
<b><font size="3">Analogies</font></b><br />
<br />
La fonctionnalité « Caller-unsafe » invite à des analogies. La plupart ne tiennent pas la route à y regarder de plus près.<br />
<br />
<b>Affirmation — Les types de référence nullables sont similaires à « Caller-unsafe ».</b> Les types de référence nullables nécessitent une inspection des méthodes et des mises à jour potentielles des signatures pour s’intégrer correctement au modèle. Ils transfèrent également la nullabilité de l’appelé vers l’appelant et incluent un mécanisme de suppression.<br />
<br />
<b>Réalité.</b> Les types de référence nullables sont une préoccupation liée au site d'utilisation qui affecte le type d'une expression. Ils n'affectent en rien la nature de l'appelant. La suppression nullable (<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">!</span>) s'applique à une seule expression ; elle indique au compilateur que la valeur est non nulle à cet endroit. Avec <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>, il n’y a pas de raccourci au niveau de l’expression ; chaque appel à un membre unsafe nécessite un bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span> <span class="br0">&#123;</span> <span class="br0">&#125;</span></span> englobant. La suppression dans le modèle unsafe est une région délimitée et vérifiable, et non une annotation par valeur.<br />
<br />
<b>Affirmation — Async est similaire à caller-unsafe. Async se propage de méthode en méthode.</b> Le mot-clé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">async</span></span> force la propagation, tout comme <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>. <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Task.Wait<span class="br0">&#40;</span><span class="br0">&#41;</span></span> est le mécanisme de suppression.<br />
<br />
<b>Réalité.</b> Le mot-clé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">async</span></span> s'apparente davantage à <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> de C# 1.0 en ce qu'il établit un contexte async pour la méthode dans lequel <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">await</span> peut être utilisé ; le type de retour de la méthode (<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Task</span>/<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">ValueTask</span>) est ce que voient les appelants. Le mécanisme de propagation est un type de retour attendable : le système de types lui-même. <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">Task.Wait<span class="br0">&#40;</span><span class="br0">&#41;</span></span> force une transition de async vers sync, ce qui s'accompagne de compromis importants. Ce n’est pas un mécanisme de suppression formel.<br />
<br />
<b>Affirmation — Le <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">@unsafe</span> au niveau du type de Swift n’est autre que l’<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> au niveau du type de C# 1.0.</b> Les deux langages utilisent le mot-clé sur un type, donc la suppression de l’<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> au niveau du type dans C# 16 semble abandonner quelque chose que Swift a conservé.<br />
<br />
<b>Réalité.</b> Les deux marqueurs partagent un mot-clé et une cible, mais sont presque orthogonaux sur le plan sémantique. Le <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">@unsafe</span> de Swift sur un type est un contrat orienté vers l’appelant : toute déclaration utilisant ce type devient implicitement <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">@unsafe</span>, et les appelants doivent encapsuler les accès dans des expressions <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>. L’<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> de C# 1.0 sur un type relevait de la portée d’implémentation : il permettait aux corps des membres du type d’utiliser des pointeurs, mais ne propageait rien aux appelants. C# 16 supprime la forme de C# 1.0 car elle ne comportait aucune information pour l’appelant. Les deux diffèrent également par leur nature : le marqueur de Swift est non permissif, imposant une obligation aux appelants, tandis que celui de C# 1.0 était permissif, débloquant des capacités au sein des membres du type. La forme Swift est la plus axée sur la sécurité des deux. Interpréter le marqueur au niveau du type de Swift à travers le prisme de C# 1.0 est une erreur.<br />
<br />
<b><font size="3">Activation de l'IA</font></b><br />
<br />
Le modèle ajoute deux éléments qu'un agent ne peut ignorer : un graphe d'appel partitionné en méthodes sûres, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> et limites ; et un compilateur qui rejette les appels <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> sans bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> englobant. Un analyseur émettra également des avertissements en cas d’absence de documentation <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">&lt;safety&gt;</span>. Chacun de ces éléments restreint le code qu’un agent peut générer tout en garantissant la réussite de la compilation, en particulier si <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">TreatWarningsAsErrors</span> est activé. Un agent générant du code pour <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">MemoryMarshal.ReadByte</span> doit soit propager <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> vers le haut jusqu’à son appelant, soit la supprimer à l’aide de gardes à la limite.<br />
<br />
Les documents <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">&lt;safety&gt;</span> font office d’instructions spécifiques à chaque API. Malgré cela, un agent de génération de code peut parfois omettre une condition de sécurité, sans que le compilateur ne s’en aperçoive. La limite informative reste toutefois utile : elle indique à un humain ou à un agent de révision de code exactement où les conditions de sécurité doivent être placées et ce qu’elles doivent protéger. Le même principe s’applique aux types de référence nullables et aux analyseurs AOT : des grammaires plus strictes réduisent l’espace de recherche, et la sortie du modèle s’adapte en conséquence.<br />
<br />
Il existe deux moyens principaux par lesquels les agents peuvent contourner le modèle :<br />
<br />
- Générer du code qui ne compile pas.<br />
  <br />
- Revenir à l'ancien modèle pour le projet et/ou activer <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">AllowUnsafeBlocks</span>. Cela s'apparente aux cas où les agents souhaitent parfois désactiver <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">TreatWarningsAsErrors</span> ou <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">IsAotCompatible</span>.<br />
<br />
Ces deux catégories sont faciles à détecter lors de la révision du code ou à identifier dans l'historique Git. « Plus facile à détecter lors de la révision du code » est le slogan de toute cette initiative.<br />
<br />
La migration vers le nouveau modèle convient également bien aux agents. Migrer le code existant vers le modèle et écrire du nouveau code dans le cadre de ce modèle ne sont pas vraiment des activités différentes. Une fois que le premier ensemble d’API de la bibliothèque d’exécution .NET aura été migré, la conformité deviendra une tâche uniforme pour l’ancien et le nouveau code.<br />
<br />
Les modèles bien établis en Rust (<span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span> fn</span>, <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span> <span class="br0">&#123;</span><span class="br0">&#125;</span></span>) se transposent clairement dans le code de type C#. Les agents peuvent effectuer une correspondance de modèles sur les corpus existants (std de Rust, bibliothèque standard de Swift) et sur les bibliothèques d'exécution .NET au fur et à mesure de leur migration. On peut soutenir que la correspondance de modèles la plus utile concerne la structure et les idiomes de la documentation de sécurité. Cet aspect de la migration serait le plus difficile à transformer en compétences. Comme indiqué précédemment, la documentation de sécurité est l'aspect le plus critique du nouveau modèle.<br />
<br />
Des recherches connexes aboutissent aux mêmes conclusions :<br />
<br />
- CRUST-Bench : A Comprehensive Benchmark for C-to-safe-Rust Transpilation (Khatry et al., COLM ’25) a montré que les agents bénéficiant du retour d’information du compilateur doublent approximativement le taux de réussite de la génération en une seule passe lors de la traduction de dépôts C vers Safe Rust.<br />
 <br />
- Gorilla: Large Language Model Connected with Massive APIs (Patil et al., NeurIPS ’24) a montré que les grands modèles de langage (LLM) disposant d’une documentation API accessible appellent les API de manière plus fiable et produisent moins d’erreurs que les modèles de référence sans assistance.<br />
<br />
- Do Users Write More Insecure Code with AI Assistants? (Perry et al., CCS ’23) a révélé que les développeurs utilisant des assistants de codage IA produisaient un code nettement moins sûr qu’un groupe témoin sans assistance, tout en jugeant leur propre production plus sûre. C’est l’écart que l’application de la sécurité au niveau du langage est censée combler.<br />
<br />
- Type-Constrained Code Generation with Language Models (Mündler et al., PLDI ’25) a montré que l’intégration des contraintes du système de types dans le décodage des LLM (plutôt que de s’appuyer sur le retour d’information a posteriori du compilateur) réduit de plus de moitié les erreurs de compilation et améliore la correction fonctionnelle à travers la synthèse, la traduction et la réparation. Des règles linguistiques plus riches façonnent la génération, et ne se contentent pas de la valider.<br />
<br />
- MultiPL-E: A Scalable and Extensible Approach to Benchmarking Neural Code Generation (Cassano et al., TSE ’23)  a montré que les performances de génération de code des LLM dépendent de la proximité syntaxique avec des langages riches en ressources, et pas seulement du volume d'entraînement dans le langage cible. C'est ce levier qui permet au corpus unsafe fn / unsafe {} de Rust de se transposer en code de type C#.<br />
<br />
- LLM Assistance for Memory Safety (Rastogi et al., ICSE ’25) s’est attaqué à la version « migration » de ce problème : déduire les annotations au niveau source nécessaires pour adapter le C hérité au dialecte sécurisé Checked C. Leur outil a déduit 86 % des annotations que les outils symboliques ne pouvaient pas fournir, sur des bases de code réelles comptant jusqu’à 20 000 lignes de code. C'est exactement le même type de travail (nommer les contraintes sur lesquelles le code existant s'appuie déjà implicitement) que nécessitera la migration vers le nouveau modèle C#.<br />
<br />
<b><font size="3">Conclusion</font></b><br />
<br />
Le nouveau modèle superpose un ensemble de modifications de compatibilité (opt-in) au code qui utilise actuellement <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> : <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> sur une signature de membre définit un contrat face à l'appelant, un bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> est requis à chaque appel à un membre <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>, et chaque membre <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> doit comporter un bloc <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #808080;">/// &lt;safety&gt;</span></span>. Trois modifications mineures complètent le modèle : le modificateur de type <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span> devient une erreur, le nouveau mot-clé <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">safe</span> marque les déclarations <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block">extern</span> dont le compilateur ne peut pas déterminer la sécurité par lui-même, et les types de pointeurs dans les signatures ne propagent plus l'insécurité de leur propre chef.<br />
<br />
Nous envisageons un avenir où C# figurera parmi un ensemble de langages choisis et reconnus pour leur application de la sécurité des types et de la mémoire. Avec ce changement de modèle, C#, Rust et Swift partagent un vocabulaire et un workflow de sécurité plus communs. Nous imaginons des équipes adoptant une vision complète de la chaîne d’approvisionnement de leurs dépendances, qu’il s’agisse de C# de bout en bout ou de C# au niveau de la couche application par-dessus Rust au niveau de la couche système. Notre propre équipe a migré de grands blocs de C++ vers C# au fil des ans précisément pour cette raison : le C# sécurisé ne s’accompagne pas d’une charge de travail liée à la vérification de la sécurité de la mémoire.<br />
<br />
Une fois qu'une équipe aura migré une partie de sa base de code vers le nouveau modèle de sécurité, elle sera probablement plus motivée à tout migrer, y compris ses dépendances. Cela pourrait s'avérer plus facile qu'il n'y paraît pour de nombreux studios de développement. Le nouveau modèle conserve C# en grande partie tel quel et modifie les modèles <span style="font-family: monospace; padding: 2px; background: #ddd; display: inline-block"><span style="color: #0000ff;">unsafe</span></span>  que la plupart des développeurs n'utilisent pas, tout en améliorant considérablement les capacités et la posture globales du langage en matière de sécurité. Nous pensons que cette fonctionnalité figure parmi les changements les plus efficaces que nous puissions apporter pour renforcer la confiance des développeurs dans cette nouvelle ère du codage.<br />
<br />
Ce projet bénéficie des contributions de : Andy Gocke, Egor Bogatov, Fred Silberberg, Jan Jones, Jan Kotas, Julien Couvreur, Mads Torgersen, Rich Lander, Tanner Gooding et d’autres.<br />
<br />
<b>Source</b> : <a rel="nofollow" href="https://devblogs.microsoft.com/dotnet/improving-csharp-memory-safety/" target="_blank">Improving C# Memory Safety</a><br />
<br />
<b>Et vous ?</b><br />
<br />
:fleche: Pensez-vous que cette présentation est crédible ou pertinente ?<br />
:fleche: Quel est votre avis sur le sujet ?<br />
<br />
<b>Voir aussi :</b><br />
<br />
:fleche: <a href="https://dotnet.developpez.com/actu/382121/Decouvrez-les-types-union-dans-C-15-par-Bill-Wagner/" target="_blank">Découvrez les types union dans C# 15, par Bill Wagner</a><br />
<br />
:fleche: <a href="https://dotnet.developpez.com/actu/372182/Exploration-des-membres-d-extension-en-C-14-preservation-de-l-enorme-quantite-de-methodes-d-extension-parametre-This-existantes-tout-en-introduisant-de-nouveaux-types/" target="_blank">Exploration des membres d'extension en C# 14, préservation de l'énorme quantité de méthodes d'extension paramètre &quot;This&quot; existantes tout en introduisant de nouveaux types</a><br />
<br />
:fleche: <a href="https://dotnet.developpez.com/actu/372078/Microsoft-presente-les-nouvelles-fonctionnalites-du-langage-de-programmation-de-C-14-membres-d-extension-affectation-par-condition-nulle-proprietes-field-stockees/" target="_blank">Microsoft présente les nouvelles fonctionnalités du langage de programmation de C# 14 : Membres d'extension, affectation par condition nulle, propriétés field stockées</a></div>


	<div style="padding:10px">

	

	
		<fieldset class="fieldset">
			<legend>Images attachées</legend>
				<div style="padding:10px">
				<img class="attach" src="https://www.developpez.net/forums/attachments/p676685d1780427508/dotnet/langages/csharp/ameliorer-securite-memoire-csharp-richard-lander/1.jpg/" alt="" />&nbsp;
			</div>
		</fieldset>
	

	

	

	</div>
]]></content:encoded>
			<category domain="https://www.developpez.net/forums/f484/dotnet/langages/csharp/">C#</category>
			<dc:creator>Richard Lander</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/d2183873/dotnet/langages/csharp/ameliorer-securite-memoire-csharp-richard-lander/</guid>
		</item>
		<item>
			<title>Plus le même serveur distant</title>
			<link>https://www.developpez.net/forums/showthread.php?t=2182857&amp;goto=newpost</link>
			<pubDate>Wed, 25 Mar 2026 14:10:40 GMT</pubDate>
			<description>Bonjour tout le monde, 
...</description>
			<content:encoded><![CDATA[<div>Bonjour tout le monde,<br />
<br />
J'espère que mon sujet ne va pas trop sentir le poisson noyé ...<br />
<br />
J'ai modifié une version des TaskbarGroups, en désignant comme serveur distant un répertoire de mon ordinateur.<br />
<br />
J'ai fait une autre version, pour tester des modifications. C'est pourtant clair que dans ce cas il faut créer une branche dans Git. Bon, routine, flemme, j'ai plutôt créé un autre projet en ajoutant 1 au nom.<br />
<br />
Les deux ont continué de fonctionner, avec des caractéristiques un peu différentes bien sûr.<br />
<br />
C'était surestimer ma mémoire, un jour il a fallu que j'ajoute une fonctionnalité, eh bien je l'ai fait sur la mauvaise version, du coup après je dois fusionner les deux pour avoir les deux fonctionnalités.<br />
<br />
Au moment où je suis satisfait du résultat, l'envoi vers le serveur distant échoue.<br />
<br />
Alors je regarde dans le paramétrage, je vois que j'ai en serveur distant le projet d'origine sur Github, bien entendu je n'ai pas les droits.<br />
<br />
Est-ce que copier du code d'un projet à l'autre peut être à l'origine de ça&nbsp;? Ça me paraît surprenant, mais je peine à me représenter ce que j'aurais pu faire d'autre qui soit arrivé à ce résultat.<br />
<br />
<br />
<br />
***<br />
<br />
Si jamais il y a ici quelqu'un qui a aussi travaillé sur un clone de ce projet, est-il aussi arrivé à la conclusion que garder ouvert le fichier xml est une mauvaise idée, vu que la fermeture demande un délai inconnu, et que la réécriture du coup se plante&nbsp;? Avec pour résultat la perte du groupe en cours d'édition. Il faut programmer deux sauvegardes pour en trouver une intacte après le plantage.<br />
Sans insister sur les données enregistrées dans le répertoire du programme ...</div>

]]></content:encoded>
			<category domain="https://www.developpez.net/forums/f484/dotnet/langages/csharp/">C#</category>
			<dc:creator>Gluups</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/d2182857/dotnet/langages/csharp/plus-meme-serveur-distant/</guid>
		</item>
		<item>
			<title><![CDATA[[resolu] Exception Manager d'extension]]></title>
			<link>https://www.developpez.net/forums/showthread.php?t=2182651&amp;goto=newpost</link>
			<pubDate>Sun, 15 Mar 2026 12:14:53 GMT</pubDate>
			<description>Bonjour, 
Dans visual studio...</description>
			<content:encoded><![CDATA[<div>Bonjour,<br />
Dans visual studio Quand je vais dans Extensions-&gt; Manages extensions , j'ai une exception :<br />
An exception was encountered while constructing the content of this frame.  This information is also logged in &quot;C:\Users\usi\AppData\Roaming\Microsoft\VisualStudio\17.0_73bb0266\ActivityLog.xml&quot;.<br />
<br />
Exception details:<br />
<i>System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---&gt; System.Runtime.InteropServices.COMException: Error HRESULT E_FAIL has been returned from a call to a COM component.<br />
   at Microsoft.VisualStudio.Setup.Configuration.ISetupConfiguration2.GetInstanceForCurrentProcess()<br />
   at Microsoft.VisualStudio.ExtensionManager.Utilities.get_CurrentVsInstance()<br />
   at Microsoft.VisualStudio.ExtensionManager.UI.ExtensionManagerDataContext..ctor(ExtensionManagerToolWindowCreationContext context, StatusReportingManager statusReportingManager, Action OnClearExtensions)<br />
   at Microsoft.VisualStudio.ExtensionManager.UI.ExtensionManagerToolWindowControl..ctor(ExtensionManagerToolWindowCreationContext context, StatusReportingManager statusReportingManager)<br />
   at Microsoft.VisualStudio.ExtensionManager.UI.ExtensionManagerToolWindow..ctor(ExtensionManagerToolWindowCreationContext context)<br />
   --- End of inner exception stack trace ---<br />
   at System.RuntimeMethodHandle.InvokeMethod(Object target, Object[] arguments, Signature sig, Boolean constructor)<br />
   at System.Reflection.RuntimeConstructorInfo.Invoke(BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo culture)<br />
   at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes, StackCrawlMark&amp; stackMark)<br />
   at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)<br />
   at System.Activator.CreateInstance(Type type, Object[] args)<br />
   at Microsoft.VisualStudio.Shell.Package.InstantiateToolWindow(Type toolWindowType, Object context)<br />
   at Microsoft.VisualStudio.Shell.Package.&lt;&gt;c__DisplayClass74_0.&lt;CreateToolWindow&gt;g__CreateToolWindowWorker|1()<br />
   at Microsoft.VisualStudio.Shell.Package.CreateToolWindow(Type toolWindowType, Int32 id, UInt32 flags, Object context, Guid persistenceGuid)<br />
   at Microsoft.VisualStudio.Shell.Package.CreateToolWindow(Type toolWindowType, Int32 id, Object context)<br />
   at Microsoft.VisualStudio.Shell.AsyncPackage.&lt;CompleteToolWindowCreationAsync&gt;d__24.MoveNext()<br />
</i><br />
<br />
Je pensais que c'était un problème de mise à jour , j'ai eu faux .<br />
<br />
Merci</div>

]]></content:encoded>
			<category domain="https://www.developpez.net/forums/f484/dotnet/langages/csharp/">C#</category>
			<dc:creator>yann458</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/d2182651/dotnet/langages/csharp/resolu-exception-manager-d-extension/</guid>
		</item>
		<item>
			<title><![CDATA[[resolu] Il n'y à plus grande monde !]]></title>
			<link>https://www.developpez.net/forums/showthread.php?t=2182648&amp;goto=newpost</link>
			<pubDate>Sat, 14 Mar 2026 22:34:44 GMT</pubDate>
			<description>Bonjour, 
Il y a plus grand...</description>
			<content:encoded><![CDATA[<div>Bonjour,<br />
Il y a plus grand monde qui utilisent visual studio ,au moins la 2022 !<br />
Aprés mise à jour , j'ai message d'erreur n'arrive pas trouver ''hubpilot'' !<br />
Dans projet c# clique droit Generate member  n'existe plus !<br />
<br />
Pas trouver grand chose sur gooooogle , car plus grand monde programment et utilisent visual studio ! moi qui est besoin de ce logiciel !<br />
<br />
<br />
J'avais fait une sauvegarde et  revenir à la version précédente qui marchent !</div>

]]></content:encoded>
			<category domain="https://www.developpez.net/forums/f484/dotnet/langages/csharp/">C#</category>
			<dc:creator>yann458</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/d2182648/dotnet/langages/csharp/resolu-n-y-plus-grande-monde/</guid>
		</item>
		<item>
			<title>Désabonner un évènement _Leave ne fonctionne pas</title>
			<link>https://www.developpez.net/forums/showthread.php?t=2182113&amp;goto=newpost</link>
			<pubDate>Sat, 14 Feb 2026 19:19:29 GMT</pubDate>
			<description><![CDATA[Bonjour,  
 
C'est un...]]></description>
			<content:encoded><![CDATA[<div>Bonjour, <br />
<br />
C'est un problème tout bête mais un peu délicat à expliquer (d'où les dessins). <br />
<br />
J'ai une ListView. Un clique sur un élément rafraîchit un Panel avec les données de l'élément cliqué. <br />
Chaque élément possède une propriété 1 ou 2. <br />
Je veux que dans le Panel suivant la valeur 1 ou 2, l'onglet d'un TabControl soit sélectionné. <br />
<br />
<img src="https://www.developpez.net/forums/attachments/p674234d1771095617/dotnet/langages/csharp/desabonner-evenement-_leave-ne-fonctionne/leavepb1.jpg/" border="0" alt="Nom : LeavePB1.jpg
Affichages : 259
Taille : 17,6 Ko"  style="float: CONFIG" /><br />
<br />
Le Panel possède un évènement Leave. <br />
Afin qu'un enregistrement automatique des données soit effectué avant d'afficher l'élément suivant de ListView qui aurait été cliqué. <br />
<br />
Quand les éléments successifs de Listview cliqués possèdent la même propriété (1 ou 2), le TabControl n'est pas modifié. <br />
<br />
<img src="https://www.developpez.net/forums/attachments/p674235d1771095796/dotnet/langages/csharp/desabonner-evenement-_leave-ne-fonctionne/leavepb2.jpg/" border="0" alt="Nom : LeavePB2.jpg
Affichages : 250
Taille : 20,2 Ko"  style="float: CONFIG" /><br />
<br />
Le problème survient quand TabControl doit changer (de 1 à 2 ou inversement). <br />
<br />
<img src="https://www.developpez.net/forums/attachments/p674236d1771095862/dotnet/langages/csharp/desabonner-evenement-_leave-ne-fonctionne/leavepb3.jpg/" border="0" alt="Nom : LeavePB3.jpg
Affichages : 226
Taille : 17,5 Ko"  style="float: CONFIG" /><br />
<br />
Leave est déclenché, alors même que la souris ne survole pas le Panel. <br />
Des enregistrement intempestifs de l'élément de ListView à peine cliqué se produisent, en cours d'affichage, avec des effets de bords et perte de données. <br />
<br />
Ma première idée a été d'empêcher l'évenement Leave du Panel de se produire pendant le rafraîchissement de Panel : <br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">&nbsp;
DonneesPanel.Leave -= DonneesPanel_Leave;</pre></td></tr></table></code><hr />
</div>puis, après l'affichage :<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">&nbsp;
DonneesPanel.Leave += DonneesPanel_Leave;</pre></td></tr></table></code><hr />
</div>Ça ne fonctionne pas. Je ne comprends pas pourquoi, alors que : <br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br /></div></td><td valign="top"><pre style="margin: 0">&nbsp;
DonneesPanel.Enter -= DonneesPanel_Enter;
DonneesPanel.Enter += DonneesPanel_Enter;</pre></td></tr></table></code><hr />
</div>Fonctionne ! <br />
<br />
Dès que TabControl doit changer, l'évènement _Leave de Panel est déclenché. <br />
Un enregistrement de la fiche qui est en train de se charger se produit, sans que je puisse l'empêcher. <br />
<br />
Merci pour votre aide</div>


	<div style="padding:10px">

	

	
		<fieldset class="fieldset">
			<legend>Images attachées</legend>
				<div style="padding:10px">
				<img class="attach" src="https://www.developpez.net/forums/attachments/p674234d1771095617/dotnet/langages/csharp/desabonner-evenement-_leave-ne-fonctionne/leavepb1.jpg/" alt="" />&nbsp;<img class="attach" src="https://www.developpez.net/forums/attachments/p674235d1771095796/dotnet/langages/csharp/desabonner-evenement-_leave-ne-fonctionne/leavepb2.jpg/" alt="" />&nbsp;<img class="attach" src="https://www.developpez.net/forums/attachments/p674236d1771095862/dotnet/langages/csharp/desabonner-evenement-_leave-ne-fonctionne/leavepb3.jpg/" alt="" />&nbsp;
			</div>
		</fieldset>
	

	

	

	</div>
]]></content:encoded>
			<category domain="https://www.developpez.net/forums/f484/dotnet/langages/csharp/">C#</category>
			<dc:creator>AMP29</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/d2182113/dotnet/langages/csharp/desabonner-evenement-_leave-ne-fonctionne/</guid>
		</item>
		<item>
			<title>C# Unity et mur interactif</title>
			<link>https://www.developpez.net/forums/showthread.php?t=2181960&amp;goto=newpost</link>
			<pubDate>Fri, 06 Feb 2026 07:30:11 GMT</pubDate>
			<description><![CDATA[J'ai développé un jeu...]]></description>
			<content:encoded><![CDATA[<div>J'ai développé un jeu (éclater des ballons) avec Unity et C#.<br />
Le jeu est fonctionnel sur une tablette. j'aimerai projeter ce jeu sur un mur pour que ce mur devienne interactif.<br />
Savez quel matériel / logiciel dois-je utiliser pour projeter ce jeu et que l'interactivité fonctionne ?<br />
Merci beaucoup</div>

]]></content:encoded>
			<category domain="https://www.developpez.net/forums/f484/dotnet/langages/csharp/">C#</category>
			<dc:creator>bard123</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/d2181960/dotnet/langages/csharp/csharp-unity-mur-interactif/</guid>
		</item>
		<item>
			<title><![CDATA[XmlSerializer - List d'entité]]></title>
			<link>https://www.developpez.net/forums/showthread.php?t=2179008&amp;goto=newpost</link>
			<pubDate>Wed, 03 Sep 2025 14:23:48 GMT</pubDate>
			<description>Bonjour, 
 
Soit le XML...</description>
			<content:encoded><![CDATA[<div>Bonjour,<br />
<br />
Soit le XML simplifié suivant <br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td valign="top"><pre style="margin: 0">  &lt;WhereFilter&gt;
&nbsp;
    &lt;FilterGroup ID=<span style="color: #FF0000;">&quot;Racine&quot;</span>&gt;
    &lt;/FilterGroup&gt;
&nbsp;
    &lt;Filter ID=<span style="color: #FF0000;">&quot;MF1FILTRE1&quot;</span>&gt;
    &lt;/Filter&gt;
&nbsp;
    &lt;FilterGroup ID=<span style="color: #FF0000;">&quot;MF1GROUPE1&quot;</span>&gt;
    &lt;/FilterGroup&gt;
&nbsp;
    &lt;Filter ID=<span style="color: #FF0000;">&quot;MF1FILTRE2&quot;</span>&gt;
    &lt;/Filter&gt;
&nbsp;
    &lt;Filter ID=<span style="color: #FF0000;">&quot;MF1FILTRE3&quot;</span>&gt;
    &lt;/Filter&gt;
&nbsp;
  &lt;/WhereFilter&gt;</pre></td></tr></table></code><hr />
</div>et la class c# pour le désérialiser<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td valign="top"><pre style="margin: 0">    <span class="br0">&#91;</span>XmlRoot<span class="br0">&#40;</span>ElementName = <span style="color: #FF0000;">&quot;WhereFilter&quot;</span>, Namespace = <span style="color: #FF0000;">&quot;&quot;</span><span class="br0">&#41;</span><span class="br0">&#93;</span>
    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> WhereFilter
    <span class="br0">&#123;</span>
        <span class="br0">&#91;</span>XmlElement<span class="br0">&#40;</span>ElementName = <span style="color: #FF0000;">&quot;FilterGroup&quot;</span>, Namespace = <span style="color: #FF0000;">&quot;&quot;</span><span class="br0">&#41;</span><span class="br0">&#93;</span>
        <span style="color: #0000ff;">public</span> List&lt;FilterGroup&gt; FilterGroup;  
&nbsp;
        <span class="br0">&#91;</span>XmlElement<span class="br0">&#40;</span>ElementName = <span style="color: #FF0000;">&quot;Filter&quot;</span>, Namespace = <span style="color: #FF0000;">&quot;&quot;</span><span class="br0">&#41;</span><span class="br0">&#93;</span>
        <span style="color: #0000ff;">public</span> List&lt;Filter&gt; Filter;
    <span class="br0">&#125;</span></pre></td></tr></table></code><hr />
</div>il y a 2 listes d'objet. Dans le principe ça foncionnne sauf que lors de l'écriture il me met en 1er les FilterGroup puis les Filter.<br />
Comme ça<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br /></div></td><td valign="top"><pre style="margin: 0">  &lt;WhereFilter&gt;
&nbsp;
    &lt;FilterGroup ID=<span style="color: #FF0000;">&quot;Racine&quot;</span>&gt;
    &lt;/FilterGroup&gt;
&nbsp;
    &lt;FilterGroup ID=<span style="color: #FF0000;">&quot;MF1GROUPE1&quot;</span>&gt;
    &lt;/FilterGroup&gt;
&nbsp;
    &lt;Filter ID=<span style="color: #FF0000;">&quot;MF1FILTRE1&quot;</span>&gt;
    &lt;/Filter&gt;
&nbsp;
    &lt;Filter ID=<span style="color: #FF0000;">&quot;MF1FILTRE2&quot;</span>&gt;
    &lt;/Filter&gt;
&nbsp;
    &lt;Filter ID=<span style="color: #FF0000;">&quot;MF1FILTRE3&quot;</span>&gt;
    &lt;/Filter&gt;
&nbsp;
  &lt;/WhereFilter&gt;</pre></td></tr></table></code><hr />
</div>Ce qui est normal.<br />
<br />
Je voudrais conserver l'ordre initial. <br />
<br />
Avez une idée de comment je pourrait déclarer ma class pour faire ça.<br />
<br />
Merci</div>

]]></content:encoded>
			<category domain="https://www.developpez.net/forums/f484/dotnet/langages/csharp/">C#</category>
			<dc:creator>Magohamoths</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/d2179008/dotnet/langages/csharp/xmlserializer-list-d-entite/</guid>
		</item>
		<item>
			<title>Affichage page web via httpClient</title>
			<link>https://www.developpez.net/forums/showthread.php?t=2178947&amp;goto=newpost</link>
			<pubDate>Sun, 31 Aug 2025 23:40:12 GMT</pubDate>
			<description>Bjr à tous, comment faire...</description>
			<content:encoded><![CDATA[<div>Bjr à tous, comment faire pour afficher une page web depuis un code c# utilisant httpclient :<br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br /></div></td><td valign="top"><pre style="margin: 0">&nbsp;
<span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">async</span> Task HttpAsync<span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
    <span style="color: #0000ff;">var</span> url = <span style="color: #FF0000;">&quot;http://www.google.com&quot;</span>; 
    <span style="color: #0000ff;">using</span> <span class="br0">&#40;</span><span style="color: #0000ff;">var</span> httpClient = <span style="color: #0000ff;">new</span> HttpClient<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="br0">&#41;</span>
    <span class="br0">&#123;</span>
        <span style="color: #0000ff;">var</span> content =<span style="color: #0000ff;">await</span> httpClient.GetStringAsync<span class="br0">&#40;</span>url<span class="br0">&#41;</span>;
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></code><hr />
</div>la &quot;var content&quot; si je débogue en utilisant le visualisateur html de visual studio m'affiche la page web correspondant à l'url, mais comment fais t-on pour afficher cette page web par programmation ?<br />
Si quelqu'un a une idée MERCI</div>

]]></content:encoded>
			<category domain="https://www.developpez.net/forums/f484/dotnet/langages/csharp/">C#</category>
			<dc:creator>xeron33</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/d2178947/dotnet/langages/csharp/affichage-page-web-via-httpclient/</guid>
		</item>
		<item>
			<title>instruction await pour methodes asynchrones</title>
			<link>https://www.developpez.net/forums/showthread.php?t=2178924&amp;goto=newpost</link>
			<pubDate>Sat, 30 Aug 2025 09:30:57 GMT</pubDate>
			<description><![CDATA[Bjr à tous, j'essaie de...]]></description>
			<content:encoded><![CDATA[<div>Bjr à tous, j'essaie de comprendre le fonctionnement des méthodes asynchrones en utilisant un exemple vu sur la doc de microsoft :<br />
<br />
<a rel="nofollow" href="https://learn.microsoft.com/fr-fr/dotnet/csharp/language-reference/operators/await" target="_blank">https://learn.microsoft.com/fr-fr/do...perators/await</a><br />
<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="33"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br />4<br />5<br />6<br />7<br />8<br />9<br />10<br />11<br />12<br />13<br />14<br />15<br />16<br />17<br />18<br />19<br />20<br />21<br />22<br />23<br />24<br />25<br />26<br />27<br />28<br />29<br />30<br />31<br />32<br /></div></td><td valign="top"><pre style="margin: 0">&nbsp;
<span style="color: #0000ff;">using</span> System;
<span style="color: #0000ff;">using</span> System.Collections.Generic;
<span style="color: #0000ff;">using</span> System.Linq;
<span style="color: #0000ff;">using</span> System.Net;
<span style="color: #0000ff;">using</span> System.Net.Http;
<span style="color: #0000ff;">using</span> System.Text;
<span style="color: #0000ff;">using</span> System.Threading.Tasks;
&nbsp;
<span style="color: #0000ff;">namespace</span> TestsSharpPcap
<span class="br0">&#123;</span>
    <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> AwaitOperator
    <span class="br0">&#123;</span>
        <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">async</span> Task Main<span class="br0">&#40;</span><span class="br0">&#41;</span>
        <span class="br0">&#123;</span>
            Task&lt;<span style="color: #0000ff;">int</span>&gt; downloading = DownloadDocsMainPageAsync<span class="br0">&#40;</span><span class="br0">&#41;</span>;
            Console.WriteLine<span class="br0">&#40;</span><span style="color: #FF0000;">$</span><span style="color: #FF0000;">&quot;<span style="color: black;"><span class="br0">&#123;</span>nameof<span class="br0">&#40;</span>Main<span class="br0">&#41;</span><span class="br0">&#125;</span></span>: Launched downloading.&quot;</span><span class="br0">&#41;</span>;
&nbsp;
            <span style="color: #0000ff;">int</span> bytesLoaded = <span style="color: #0000ff;">await</span> downloading;
            Console.WriteLine<span class="br0">&#40;</span><span style="color: #FF0000;">$</span><span style="color: #FF0000;">&quot;<span style="color: black;"><span class="br0">&#123;</span>nameof<span class="br0">&#40;</span>Main<span class="br0">&#41;</span><span class="br0">&#125;</span></span>: Downloaded <span style="color: black;"><span class="br0">&#123;</span>bytesLoaded<span class="br0">&#125;</span></span> bytes.&quot;</span><span class="br0">&#41;</span>;
        <span class="br0">&#125;</span>
&nbsp;
        <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">async</span> Task&lt;<span style="color: #0000ff;">int</span>&gt; DownloadDocsMainPageAsync<span class="br0">&#40;</span><span class="br0">&#41;</span>
        <span class="br0">&#123;</span>
            Console.WriteLine<span class="br0">&#40;</span><span style="color: #FF0000;">$</span><span style="color: #FF0000;">&quot;<span style="color: black;"><span class="br0">&#123;</span>nameof<span class="br0">&#40;</span>DownloadDocsMainPageAsync<span class="br0">&#41;</span><span class="br0">&#125;</span></span>: About to start downloading.&quot;</span><span class="br0">&#41;</span>;
            <span style="color: #0000ff;">var</span> client = <span style="color: #0000ff;">new</span> HttpClient<span class="br0">&#40;</span><span class="br0">&#41;</span>;
            <span style="color: #0000ff;">byte</span><span class="br0">&#91;</span><span class="br0">&#93;</span> content = <span style="color: #0000ff;">await</span> client.GetByteArrayAsync<span class="br0">&#40;</span><span style="color: #FF0000;">&quot;http://www.google.com/&quot;</span><span class="br0">&#41;</span>;
            Console.WriteLine<span class="br0">&#40;</span><span style="color: #FF0000;">$</span><span style="color: #FF0000;">&quot;<span style="color: black;"><span class="br0">&#123;</span>nameof<span class="br0">&#40;</span>DownloadDocsMainPageAsync<span class="br0">&#41;</span><span class="br0">&#125;</span></span>: Finished downloading.&quot;</span><span class="br0">&#41;</span>;
            <span style="color: #0000ff;">return</span> content.Length;
        <span class="br0">&#125;</span>
    <span class="br0">&#125;</span>
<span class="br0">&#125;</span></pre></td></tr></table></code><hr />
</div>Le problème que j'ai est que quand la tache &quot;DownloadDocsMainPageAsync&quot; est lancée et qu'elle arrive à l'opérateur await elle s'exécute et termine le programme sans exécuter le reste du code :<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br />3<br /></div></td><td valign="top"><pre style="margin: 0">&nbsp;
Console.WriteLine<span class="br0">&#40;</span><span style="color: #FF0000;">$</span><span style="color: #FF0000;">&quot;<span style="color: black;"><span class="br0">&#123;</span>nameof<span class="br0">&#40;</span>DownloadDocsMainPageAsync<span class="br0">&#41;</span><span class="br0">&#125;</span></span>: Finished downloading.&quot;</span><span class="br0">&#41;</span>;
<span style="color: #0000ff;">return</span> content.Length;</pre></td></tr></table></code><hr />
</div>ce qui donne comme résultat :<br />
<br />
DownloadDocsMainPageAsync: About to start downloading.<br />
Main: Launched downloading.<br />
<br />
au lieu comme le stipule le cours :<br />
<br />
// Output similar to:<br />
// DownloadDocsMainPageAsync: About to start downloading.<br />
// Main: Launched downloading.<br />
// DownloadDocsMainPageAsync: Finished downloading.<br />
// Main: Downloaded 27700 bytes.<br />
<br />
Ils précisent : &quot;L’opérande d’une expression await doit fournir une notification lorsqu’une tâche se termine. En général, un délégué est appelé lorsque la tâche se termine, que ce soit une réussite ou un échec. La section await de la spécification du langage C# fournit les détails sur la façon dont ces notifications sont implémentées.&quot;<br />
mais je n'arrive pas à voir d'exemples précis, si quelqu'un a une idée MERCI</div>

]]></content:encoded>
			<category domain="https://www.developpez.net/forums/f484/dotnet/langages/csharp/">C#</category>
			<dc:creator>xeron33</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/d2178924/dotnet/langages/csharp/instruction-await-methodes-asynchrones/</guid>
		</item>
		<item>
			<title><![CDATA[Comment compiler libiec61850 pour pouvoir l'utiliser comme DLL en C# ?]]></title>
			<link>https://www.developpez.net/forums/showthread.php?t=2178139&amp;goto=newpost</link>
			<pubDate>Fri, 18 Jul 2025 19:10:57 GMT</pubDate>
			<description>Bonjour, 
Je ne suis pas sûr...</description>
			<content:encoded><![CDATA[<div>Bonjour,<br />
Je ne suis pas sûr d'être dans le bon forum, mais bon voilà, ma question concerne au final le C#.<br />
(Changez la rubrique du post si vous pensez que cela doit être fait).<br />
<br />
Voici l'exposé de mon problème. <b>Je voudrais faire un projet en C# qui tourne autour du protocole industriel iec61850.</b><br />
Mais j'ai besoin d'une librairie open-source que j'ai beaucoup de mal à compiler.<br />
<br />
Cette librairie, c'est libiec61850 de mz-automation qui a été écrite en C : la voici :<br />
<a rel="nofollow" href="https://github.com/mz-automation/libiec61850" target="_blank">https://github.com/mz-automation/libiec61850</a><br />
On apprend dans l'intro qu'il est possible de la compiler en .DLL pour C#.<br />
Et mz-automation fournit aussi un wrapper pour .Net qui permet d'utiliser facilement toutes les fonctions de la librairie en C#.<br />
<br />
Cette librairie est d'ailleurs utilisée (sous forme de DLL aussi, mais ancienne et incomplète) dans le magnifique logiciel open-source <b>IED-Explorer</b> (hébergé avec des exécutables sur SourceForge) : programme qui marche très bien au demeurant.<br />
<br />
J'ai pris mon courage à deux mains, et j'ai tenté de compiler libiec61850.<br />
(Autre remarque, même si je vais utiliser cette DLL sous Windows, j'ai une intuition qui me dit que ce sera plus facile de produire cette DLL sous Linux).<br />
<br />
<b><u>Voici mon mode opératoire (sous Ubuntu), mais je n'arrive pas à atteindre l'objectif final.</u></b><br />
<br />
<b>1)</b> d'abord je me suis assuré d'avoir un compilateur cross-platform, j'ai fait :<br />
sudo apt-get install gcc-mingw-w64<br />
<br />
<b>2)</b> ensuite, j'ai vérifié que j'ai un cmake récent :<br />
cmake --version<br />
3.28.3<br />
<br />
<b>3)</b> J'ai téléchargé le SDK de WinPcap, càd WpdPack_4_1_2.zip dont j'extrais le contenu Lib et Include et je les place dans les sources :<br />
Third_Party/WinPcap/<br />
 <br />
<b>4)</b> je crée alors un dossier build dans le dossier racine de la librairie : ./libiec61850/build<br />
je vais dans ce dossier build et je fais : CMake avec les deux points. Ces deux points vont chercher en réalité CMakeLists.txt un niveau plus haut :<br />
cmake ..<br />
<br />
<b>5)</b> cela semble construire correctement un fichier make, dirait-on.<br />
<br />
<b>6)</b> ensuite je me place à nouveau dans le dossier ./libiec61850/build, et de là, dans mon terminal, je fais :<br />
make TARGET=WIN32<br />
<br />
<b>7)</b> là, j'ai un magnifique défilé de compilation, apparemment sans aucun message d'erreur (cool), et cela semble<br />
me construire :<br />
- un fichier compilé nommé <b>libiec61850.so</b> de 1,1 Mo.<br />
- un fichier compilé nommé <b>libiec61850.so.1.6.0</b> de 1,1 Mo.<br />
- un fichier compilé nommé <b>libiec61850.a</b> de 1,8 Mo.<br />
<br />
Mais aucune DLL ?<br />
<br />
J'ai cherché partout des exemples de compilation, mais je ne sais toujours pas comment compiler en DLL à mon stade de connaissance ?<br />
Quelqu'un peut me dire quelle commande je dois insérer ou modifier pour obtenir cette fameuse librairie au format libiec61850.dll ?<br />
<br />
Un grand merci d'avance pour votre aide. :calim2:</div>

]]></content:encoded>
			<category domain="https://www.developpez.net/forums/f484/dotnet/langages/csharp/">C#</category>
			<dc:creator>calogerogigante</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/d2178139/dotnet/langages/csharp/compiler-libiec61850-pouvoir-l-utiliser-dll-csharp/</guid>
		</item>
		<item>
			<title>Coder JavaScript depuis C#</title>
			<link>https://www.developpez.net/forums/showthread.php?t=2178102&amp;goto=newpost</link>
			<pubDate>Thu, 17 Jul 2025 09:00:50 GMT</pubDate>
			<description>Bonjour à tous, 
Je...</description>
			<content:encoded><![CDATA[<div>Bonjour à tous,<br />
Je souhaiterais pouvoir coder du javascript depuis une appiication console c# Framework .net 4.8.<br />
J'ai essayé d'ajouter à mon code :<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">&nbsp;
<span style="color: #0000ff;">using</span> System.Runtime.InteropServices;</pre></td></tr></table></code><hr />
</div>Quand j'essaie d'utiliser Interop :<br />
<div class="bbcode_container">
	<div class="bbcode_description">Code:</div>
	<hr /><code class="bbcode_code"><table cellspacing="0" cellpadding="0"><tr><td valign="top" width="26"><div style="border: 1px dashed gray; padding-left: 5px; padding-right: 5px; margin-right: 5px; text-align: right; font-family: monospace">1<br />2<br /></div></td><td valign="top"><pre style="margin: 0">&nbsp;
Interop s;</pre></td></tr></table></code><hr />
</div>J'ai l'erreur : Erreur de compilateur CS0122<br />
<br />
<br />
&quot;membre&quot; est inaccessible en raison de son niveau de protection<br />
<br />
 Je n'arrive pas à trouver une bonne solution, si quelqu'un a une idée. MERCI</div>

]]></content:encoded>
			<category domain="https://www.developpez.net/forums/f484/dotnet/langages/csharp/">C#</category>
			<dc:creator>xeron33</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/d2178102/dotnet/langages/csharp/coder-javascript-csharp/</guid>
		</item>
		<item>
			<title>Comme le fait Inspect.</title>
			<link>https://www.developpez.net/forums/showthread.php?t=2178046&amp;goto=newpost</link>
			<pubDate>Mon, 14 Jul 2025 06:55:10 GMT</pubDate>
			<description>Bonjour à tous, 
 
Je suis en...</description>
			<content:encoded><![CDATA[<div>Bonjour à tous,<br />
<br />
Je suis en cours de développement d'une application me permettant d'utiliser une interface (DAW-Midi) vers une application (DASLIGHT) écrite en QT5 afin de pouvoir faciliter la manipulation de paramétrage sur cette application.<br />
<br />
La plupart des boutons de cette application sont accessibles par une commande en utilisant le protocole OSC, mais malheureusement, il me manque la possibilité d'accéder à certains éléments (Edit). <br />
<br />
J'ai demandé au programmateur de cette application s'il pouvait ouvrir ces éléments, mais il m'a répondu que ce n'était pas dans sa priorité.<br />
<br />
J'arrive à envoyer un clique par un sendmessage vers cette application, mais je n'ai pas toutes les informations (position x/y) pour pouvoir l'automatiser.<br />
<br />
Si j'utilise l'application &quot;inspect.exe&quot; elle me donne toute une arborescence des objets de cette l'application avec les informations qu'il me faudrait.<br />
<br />
Savez-vous comment il est possible d'obtenir la liste de ces objets et leurs paramètres à partir du handle de l'application comme le fait l'application &quot;inspect.exe&quot; ?<br />
<br />
Merci beaucoup pour votre aide.<br />
<br />
À bientôt.<br />
<br />
François.</div>

]]></content:encoded>
			<category domain="https://www.developpez.net/forums/f484/dotnet/langages/csharp/">C#</category>
			<dc:creator>wsixpo82</dc:creator>
			<guid isPermaLink="true">https://www.developpez.net/forums/d2178046/dotnet/langages/csharp/inspect/</guid>
		</item>
	</channel>
</rss>
