Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Champion-fråga: https://github.com/dotnet/csharplang/issues/9704
Sammanfattning
Vi uppdaterar definitionen av unsafe i C# från att referera till platser där pekartyper används, till att vara platser där minnet som inte hanteras av körningen avrefereras. Dessa platser är platser där minnessäkerhet uppstår och ansvarar för huvuddelen av CVE:er (vanliga sårbarheter och exponeringar) som kategoriseras som minnessäkerhetsproblem.
// Under the proposed rules:
void M()
{
int i = 1;
int* ptr = &i; // Allowed: creating a pointer is not itself unsafe
unsafe
{
Console.WriteLine(*ptr); // Dereference of memory not managed by the runtime. This is unsafe.
ref int intRef = Unsafe.AsRef(ptr); // Conversion of memory not managed by the runtime to a `ref`. This is unsafe.
}
}
namespace System.Runtime.CompilerServices
{
public static class Unsafe
{
unsafe public static ref T AsRef<T>(void* source) { /* ... */ } // `unsafe` marks the member as *requires-unsafe*.
}
}
Motivation
Bakgrund för den här funktionen finns också i https://github.com/dotnet/designs/blob/main/accepted/2025/memory-safety/caller-unsafe.md, som spårar de bredare ekosystemändringar som kommer att behövas som en del av det här förslaget.
Dessa inkluderar BCL-uppdateringar för att korrekt kommentera metoder som osäkra, samt verktygsuppdateringar för bättre förståelse av var minnet är osäkert. Specifikt för C# vill vi se till att minnessäkerhet spåras korrekt av språket. idag kan det vara svårt att titta på ett program holistiskt och förstå alla platser där minnet är osäkert. Detta beror på att olika hjälpare som System.Runtime.CompilerServices.Unsafe, System.Runtime.InteropServices.Marshaloch andra inte uttrycker att de bryter mot minnessäkerheten och behöver särskild hänsyn. Metoder som sedan använder dessa hjälpverktyg är inte omedelbart uppenbara, och när du granskar kod för minnessäkerhetsproblem (antingen i förväg när du gör granskning eller när du försöker fastställa orsaken till en säkerhetsrisk som rapporteras) kan det vara svårt att hitta de platser som kan bidra till problem.
Tidigare har I C# refererat unsafe till ett specifikt minnessäkerhetshål: förekomsten av pekartyper. I det ögonblick då en pekartyp inte längre är involverad, är C# helt glad över att låta minnet osäkert ligga latent i kod. Det är det här problemet som vi vill ta itu med med den här utvecklingen av unsafe i C# och det .NET ekosystemet, märkningsområden där minnessäkerhet potentiellt kan uppstå, vilket gör det lättare för granskare och granskare att förstå gränserna för potentiell minnessäkerhet i ett program. Viktigt är att detta innebär att vi kommer att ändra innebörden av unsafe, inte bara utöka den. Förekomsten av en pekare är inte i sig osäker. den osäkra åtgärden avrefererar pekaren. Detta utvidgar vidare till typerna själva; kan inte vara osäkra i sig. Det är bara åtgärden att använda en typ som kan vara osäker, inte förekomsten av den typen.
För att den här informationen ska kunna flöda genom systemet måste vi därför ha ett sätt att markera själva metoderna som unsafe. I dag, unsafe eftersom en metodmodifierare inte har någon extern inverkan, tillåter den bara att pekare används i medlemmens signatur och brödtext. Framöver kommer unsafe en modifierare faktiskt offentligt att ändra medlemmens innebörd. Det indikerar att medlemmen har minnessäkerhetsproblem och att all användning måste valideras manuellt av programmeraren med hjälp av medlemmen. Detta är en utvidgning av det existerande menande av unsafe: unsafe på ett förkroppsliga lokaliserar granskaskyldigheten till det förkroppsligar, stunder unsafe på en häfte fördjupa det åtagande till anroparen.
Det här är en potentiellt stor icke-bakåtkompatibel ändring för vissa segment i C#-användarbasen. Vår förhoppning är att för många av våra användare är detta effektivt transparent, och att uppdatera till de nya reglerna kommer att vara sömlöst. Men med tanke på att vissa stora API-ytor som stora delar av reflektion kan behöva markeras unsafe, tror vi att det är troligt att det kommer att behöva finnas en anständig ramp till de nya reglerna för att undvika att helt dela upp ekosystemet.
Brytande förändringar
Följande icke-bakåtkompatibla ändringar kan observeras när du uppdaterar till en kompilator som implementerar den här språkfunktionen.
- Om de uppdaterade minnessäkerhetsreglerna är aktiverade (vilket kan vara standardalternativet eller till och med det enda alternativet i en framtida .NET version):
-
unsafepå en medlem markerar det nu också som kräver osäkert, vilket innebär att anropare måste vara i enunsafekontext och åsidosättningar kan inte varaunsafeom basmedlemmen är säker. -
unsafepå en medlem eller en typ introducerar inte automatiskt enunsafekontext, vilket innebär att explicitaunsafeblock måste användas runtunsafeåtgärder i medlemsorgan och initierare. -
externmedlemmar och fält i explicit layout kräver en explicitunsafe/safenyckelord i deklarationen. -
stackallocunder vissa förhållanden kräver ettunsafesammanhang. -
unsafemodifieraren är ett fel på typdeklarationer, statiska konstruktorer och destruktörer, eftersom det inte har någon effekt.
-
- Under en ny langversion:
- Lambda-slutsatsdragning kan överväga fler kandidater, vilket resulterar i tvetydigheter i överlagringslösningen.
-
safeär nu ett kontextuellt nyckelord som kan bryta kod som använde det som en typ.
Detaljerad design
Terminologi: vi anropar medlemmar som kräver osäkert (tidigare kallat anropare-osäkert) om
- enligt de uppdaterade reglerna för minnessäkerhetär de märkta
unsafe, - under de äldre minnessäkerhetsreglernainnehåller de pekare i signaturen.
Syntax
I det här förslaget införs:
- ett nytt
safekontextuellt nyckelord som kan tillämpas påexternmedlemmar och fält i explicit layout, - och
unsafeuttryck (unsafe(expression)), som beskrivs i osäkra uttryck.
Den här nya syntaxen är tillgänglig under nya LangVersion, men oavsett anmäl dig, under förutsättningen att vi försöker göra det så att allt du måste göra när du är anmäld, får du göra det innan du anmäler dig.
Befintliga unsafe regler
Den befintliga C#-specifikationen har ett stort avsnitt som ägnas åt unsafe: §24 Osäker kod. Det definieras som villkorligt normativt eftersom det inte krävs för att en giltig C#-kompilator ska ha stöd unsafe för funktionen. Mycket av det som för närvarande anses vara villkorligt normativt kommer inte längre att vara det efter denna ändring, eftersom de flesta av definitionen av pekare inte längre anses vara osäkra i sig.
Pekartyper, fasta och flyttbara variabler, alla pekaruttryck (förutom indirekt pekare, åtkomst till pekaremedlemmar och åtkomst till pekarelement) och -instruktionen fixed betraktas unsafeinte längre och finns i normal C# utan krav på att användas i en unsafe kontext. På samma sätt är det också helt lagligt att deklarera en buffert med fast storlek eller en initierad stackalloc i säker C#. I alla dessa fall är det bara att komma åt det minne som är osäkert.
Viktigt är att dessa pekaravslappningar gäller oavsett om en sammansättning väljer de uppdaterade minnessäkerhetsreglerna.
Endast åtgärder som faktiskt avreferering eller på annat sätt direkt åtkomst till spetsigt minne fortsätter att kräva en unsafe kontext.
Detta möjliggör en inkrementell migreringssökväg: användare kan omforma befintlig kod genom att flytta unsafe inåt när medlemmen hanterar risken internt eller utåt när anroparen måste delta i granskningen innan de vänder på den löpande opt-in-växeln.
Med tanke på den omfattande omskrivningen av både kodavsnittet unsafe och andra delar av C#-specifikationen som ingår i den här ändringen skulle det vara otymplig och sannolikt inte användbart att tillhandahålla en rad-för-rad-diff av de befintliga reglerna i specifikationen. I stället ger vi en översikt över ändringen som ska utföras i ett visst avsnitt, samt specifika nya regler för vad som tillåts i unsafe kontexter.
Omdefiniera uttryck som kräver osäkra kontexter
Följande uttryck kräver en unsafe kontext när de används:
- Indirekta pekare
- Åtkomst till pekarmedlem
- Åtkomst till pekarelement
- Anrop till funktionspekare
- Elementåtkomst på en buffert med fast storlek
-
stackallocenligt de villkor som definieras nedan
Förutom dessa uttryck kan uttryck och uttryck även villkorsstyrt kräva en unsafe kontext om de är beroende av någon symbol som är markerad som unsafe. Om du till exempel anropar en metod som kräver osäkert kan invocation_expression kräva en unsafe kontext. Instruktioner med inbäddade anrop (till exempel s, foreachoch liknande) kan också kräva en unsafe kontext när de använder en medlem som usingkräver osäkert innehåll.
När vi säger "kräver en osäker kontext" eller liknande i det här dokumentet innebär det att generera ett fel om att konstruktionen kräver att en unsafe kontext används.
Note
Det här avsnittet behöver förmodligen utökas för att formellt deklarera vad varje uttryck och -instruktion måste överväga för att kräva en unsafe kontext.
Pekartyper
Som nämnts blir pekare inte längre i sig osäkra. Referenser till osäkra kontexter i §24.3 tas bort. Pekartyper finns i normal C# och kräver unsafe inte att de ska finnas. Typdefinitionerna bör arbetas in i §8.1 och dess följande avsnitt, som andra typer.
På samma sätt bör pekarkonverteringar bearbetas till §10, med referenser till unsafe kontexter borttagna.
På samma sätt bör pekaruttryck, förutom indirekt pekare, åtkomst till pekaremedlemmar och åtkomst till pekarelement, bearbetas till §12, med referenser till unsafe kontexter borttagna. Ingen semantik ändrar innebörden av dessa uttryck; den enda ändringen är att de inte längre kräver en unsafe kontext att använda.
För indirekt pekare, åtkomst till pekaremedlemmar och åtkomst till pekarelement förblir dessa operatorer osäkra eftersom dessa åtkomstminnen som inte hanteras av körningen. De finns kvar i §24 och fortsätter att kräva att ett unsafe sammanhang används. All användning utanför en unsafe kontext är ett fel.
Inga semantik om dessa operatorer ändras. De fortsätter fortfarande att betyda exakt samma sak som de gör idag. Dessa uttryck måste alltid förekomma i en unsafe kontext.
Den fasta instruktionen flyttas till §13, med referenser till unsafe kontexter borttagna.
Funktionspekare har ännu inte införlivats i C#-huvudspecifikationen, men de påverkas på liknande sätt. allt utom funktionspekaranrop flyttas till standardspecifikationen.
Ett uttryck för anrop av funktionspekare måste alltid ske i en unsafe kontext.
Buffertar med fast storlek
Artikeln för buffertar med fast storlek liknar pekare. Definitionen av en buffert med fast storlek är inte i sig farlig och flyttas till §16.3. Det är på samma sätt säkert att komma åt en buffert med fast storlek i ett uttryck, såvida inte uttrycket inträffar som primary_expression för en element_access. Dessa utvärderas som en pointer_element_access, vilket är osäkert enligt reglerna ovan.
Stackallokering
Återigen är berättelsen för stackallokering mycket lik pekare. Det är inte längre osäkert att konvertera en stackalloc till en pekare. Det är den här pekarens fördröjning som är osäker. Vi lägger dock till en ny regel:
En stackalloc_expression är osäker om alla följande instruktioner är sanna:
-
Stackalloc_expression konverteras till en
Span<T>eller enReadOnlySpan<T>. - Stackalloc_expression har ingen stackalloc_initializer.
-
Stackalloc_expression används i en medlem som har tillämpats
SkipLocalsInitAttribute.
I dessa sammanhang kan det resulterande stackutrymmet ha okänt minnesinnehåll, och det konverteras till en typ som ger en säker omslutning kring ohanterad minnesåtkomst. Detta bryter mot avtalet för Span<T> och ReadOnlySpan<T>, och därför måste vara föremål för extra granskning av författaren och granskarna av sådan kod.
Till skillnad från andra ändringar unsafe av regler som är avslappningar är detta en åtstramning, och därför gäller det endast under opt-in för de uppdaterade minnessäkerhetsreglerna för att undvika en paus.
Note
Det innebär att det alltid är säkert att tilldela en stackalloc pekare, oavsett kontext.
Observera att en stackalloc av en hanterad typ fortfarande är ett fel.
sizeof
För vissa fördefinierade typer sizeof har alltid varit konstant och säker (§12.8.19) och det förblir oförändrat.
För andra typer sizeof används för att kräva osäker kontext (§24.6.9) men är nu säker oavsett om du anmäler dig till de uppdaterade minnessäkerhetsreglerna.
Åsidosättande, arv och implementering
Det är ett minnessäkerhetsfel att lägga unsafe till på medlemsnivå i en åsidosättning eller implementering av en medlem som inte kräver osäker ursprungligen, eftersom anropare kanske använder basdefinitionen och inte ser något tillägg av unsafe av en härledd implementering.
Delegater och lambdas
Det är ett minnessäkerhetsfel att konvertera en medlem som kräver osäker till en ombudstyp utanför kontexten unsafe .
Delegera typer och funktionstyper kan inte vara osäkra.
Det är ett kompileringsfel att tillämpa unsafe på en lambda-symbol.
extern
Eftersom extern metoder är till interna platser som inte kan garanteras av körningen kan kompilatorn inte avgöra om de är säkra eller osäkra.
Även metoder som bara tar unmanaged parametrar efter värde kan inte anropas på ett säkert sätt av C#, eftersom den anropskonvention som används för metoden kan anges felaktigt av användaren och måste verifieras manuellt genom granskning.
Enligt de uppdaterade reglerna för minnessäkerhet kräver kompilatorn därför att varje extern metod uttryckligen markeras som antingen unsafe eller safe.
extern metoder från sammansättningar som använder äldre minnessäkerhetsregler betraktas inte implicit unsafe eftersom extern anses vara implementeringsinformation som inte är en del av den offentliga ytan.
extern garanteras inte bevaras i referenssammansättningar.
Observera att detta skiljer sig från det kompatibilitetsläge som även gäller för äldre regelsammansättningar eftersom metoder med pekare i signatur alltid skulle behöva en osäker kontext på anropsplatsen.
Osäkra modifierare och kontexter
Idag, som omfattas av den osäkra kontextspecifikationen, unsafe beter sig på ett lexikalt sätt och markerar hela texttexttexten unsafe som ingår i blocket som ett unsafe sammanhang (förutom iteratororgan) och även några omgivande kontexter i händelse av deklarationer:
class A : Attribute
{
public A(object o) { }
}
class C
{
[A(default(int*[]))] void M1() { } // error: using pointers outside `unsafe` context
[A(default(int*[]))] unsafe void M2() { } // ok
}
Med opt-in till de uppdaterade minnessäkerhetsreglerna unsafe markerar en medlem det som kräver osäkert, utökar granskningsskyldigheten till anroparen och introducerar inte ett unsafe sammanhang (i stället upprättar unsafe endast explicita unsafe regioner i brödtexten kontexter).
unsafe i följande deklarationer uppstår ett fel eftersom det inte längre har någon betydelse:
-
delegate. - statisk konstruktor,
- Destructor
- typdeklaration (
class,structosv.).
unsafe på en konstruktor introducerar en unsafe kontext i dess initializer, dvs. en unsafe konstruktor kan kalla en kräver-osäkerbase eller this konstruktor.
Typer med parameterlösa kräver osäkra konstruktorer uppfyller inte villkoret new() .
På samma sätt och dessutom uppfyller structs med parameterlösa kravsäkra konstruktorer inte villkoret struct .
unsafe på en medlem tillämpas inte på några kapslade anonyma eller lokala funktioner i medlemmen.
Detsamma gäller för anonyma och lokala funktioner som deklareras i ett unsafe block (de är fortfarande i ett unsafe sammanhang som alltid, men de blir inte kräver osäkra).
Om du vill markera en lokal funktion som kräver osäker måste den manuellt markeras som unsafe.
Lambdas kan inte markeras som kräver osäkert (nyckelordet unsafe tillåts inte för dem).
När en medlem är partialmåste båda delarna komma överens om unsafe modifieraren, oförändrade från C#-reglerna i dag.
partial class C1
{
public partial void M1(); // Error: both parts must be unsafe, or neither can be
public partial unsafe void M2();
}
partial class C1
{
public unsafe partial void M1() => Console.WriteLine("hello world");
public partial void M2() => Console.WriteLine("hello world"); // Error: both parts must be unsafe, or neither can be
}
För egenskaper get , och set/init accessorer kan deklareras oberoende som unsafe; markera hela egenskapen som unsafe innebär att både get och-åtkomsterna set/init är osäkra.
Det går för närvarande inte att placera några modifierare på händelseåtkomster, och det här förslaget ändrar inte att, dvs. och remove händelseåtkomster, add inte kan deklareras oberoende som unsafe.
Endast om hela händelsen har markerats som unsafeinnebär det att åtkomsterna är osäkra, annars är de säkra.
Fields
unsafe i ett fält markeras det också som kräver osäkert och introducerar inte någon unsafe kontext i dess initialiserare.
Kompatibilitetsläget gäller även för fält.
Att markera en egenskap eller händelse som unsafe inte gör dess bakgrundsfält osäkert.
I en typ med [StructLayout(LayoutKind.Explicit)] eller [ExtendedLayout]måste alla instansfält markeras antingen safe eller unsafe.
Om fältet är "dolt" bakom en automatisk egenskap eller fältliknande händelse safe/unsafe flyttas kravet till den automatiska egenskapen eller fältliknande händelsen i stället.
Metadata
När en sammansättning kompileras med de nya minnessäkerhetsreglerna markeras den med MemorySafetyRulesAttribute (beskrivs nedan) och fylls i med 15 som språkversion. Detta är en signal till alla underordnade konsumenter att alla medlemmar som definierats i sammansättningen kommer att tillskrivas RequiresUnsafeAttribute (beskrivs nedan) om en unsafe kontext krävs för att anropa dem.
En medlem i en sådan sammansättning som inte är markerad med RequiresUnsafeAttribute kräver inte att en unsafe kontext anropas, oavsett vilka typer som ingår i medlemmens signatur.
Det är ett fel att tillämpa MemorySafetyRulesAttribute eller RequiresUnsafeAttribute på någon symbol explicit i källan.
Kompilatorn ignorerar RequiresUnsafeAttribute-markerade medlemmar från sammansättningar som använder äldre minnessäkerhetsregler (i stället används kompatibilitetsläget där).
När en icke-typmedlem har markerats som unsafe, syntetiserar kompilatorn ett RequiresUnsafeAttribute program på medlemmen i metadata.
När en användarriktad medlem som kräver osäkert genererar dolda medlemmar, till exempel en automatisk egenskaps get/set-metoder, är både den användarriktade medlemmen och eventuella dolda medlemmar som genereras av den användarriktade medlemmen alla osäkra och RequiresUnsafeAttribute tillämpas på dem alla.
Definitionen MemorySafetyRulesAttribute och RequiresUnsafeAttribute syntetiseras av kompilatorn om det behövs enligt välkända standardregler för medlemmar.
namespace System.Runtime.CompilerServices
{
/// <summary>Indicates the language version of the memory safety rules used when the module was compiled.</summary>
[AttributeUsage(AttributeTargets.Module, Inherited = false)]
public sealed class MemorySafetyRulesAttribute : Attribute
{
/// <summary>Initializes a new instance of the <see cref="MemorySafetyRulesAttribute"/> class.</summary>
/// <param name="version">The language version of the memory safety rules used when the module was compiled.</param>
public MemorySafetyRulesAttribute(int version) => Version = version;
/// <summary>Gets the language version of the memory safety rules used when the module was compiled.</summary>
public int Version { get; }
}
[AttributeUsage(AttributeTargets.Event | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)]
public sealed class RequiresUnsafeAttribute : Attribute
{
}
}
Kompatibilitetsläge
I kompatibilitetssyfte och för att minska antalet falska negativa identifieringar som inträffar när de nya reglerna aktiveras har vi en reservregel för moduler som inte har uppdaterats till de nya reglerna. För sådana moduler anses en medlem vara osäker på krav om den innehåller en pekare eller funktionspekare någonstans bland dess parametertyper eller returtyp (kan kapslas i en typ som inte är pekare, t.ex. int*[]).
Observera att detta inte gäller för pekare i villkorstyper (t.ex. where T : I<int*[]>) eftersom de inte skulle behöva osäker kontext på anropsplatserna tidigare heller.
Detta inkluderar inte ersatta generiska parametrar (t.ex. metod I<T>.M(T) när den ersätts T med int*[]) eftersom det inte finns något typsäkert sätt för målmedlemmen att använda den pekartypen för något ändå.
Sådana kompatibilitetslägen kräver att osäkra medlemmar kräver att en unsafe kontext används även från uppringare som inte har valt de uppdaterade reglerna för minnessäkerhet.
Det bör undvika en "dip" där bara uppdatering av LangVersion (men inte uppdatering av version av minnessäkerhetsregler) gör de flesta pekaråtgärder säkra (inklusive anropande funktioner med pekare i signatur som sannolikt kommer att markeras som kräver osäker när de väljs in i de uppdaterade reglerna), och därmed göra koden mindre skyddad i det här migreringsfönstret.
VB
Vi behöver inte lägga till stöd för Visual Basic för medlemmar som kräver osäkert eftersom det inte finns några unsafe kontexter i VB idag och inget sätt att arbeta med pekare där heller.
unsafe Uttryck
Ett unsafe uttryck introducerar en minimal unsafe kontext för utvärdering av ett enda uttryck. Det är användbart i situationer där ett unsafe block i onödan skulle utvidga omfånget unsafe , eller där unsafe block inte kan användas syntaktiskt (till exempel i catch filter, fältinitierare, konstruktorinitierare och operandpositionen awaitför ).
Syntax
En unsafe_expression läggs till som en primary_no_array_creation_expression:
unsafe_expression
: 'unsafe' '(' expression ')'
;
Det är föremål för samma AllowUnsafeBlocks krav som nyckelordet unsafe någon annanstans.
Semantik
En unsafe_expression upprättar en unsafe kontext för att utvärdera dess uttryck. Det innebär att pekaravrefereringar, funktionspekaranrop och anrop till medlemmar som kräver osäkert tillåts i det inneslutna uttrycket. Typen och värdet för unsafe_expression är typen och värdet för det omslutna uttrycket.
Kontexten unsafe som upprättas av en unsafe_expression sträcker sig inte längre än dess avslutande parentes.
Exempel på motivation och migrering
Flera syntaktiska positioner tar inte emot unsafe block alls, men kan ändå innehålla underuttryck som anropar kräver osäkra medlemmar. Utan unsafe uttryck kräver migrering av sådan kod att det osäkra underuttrycket extraheras till en lokal hjälpfunktion eller en tillfällig variabel, vilket döljer avsikten och ökar verbositeten.
awaitpå en metod som kräver osäker. Ett await uttryck kan inte visas i ett unsafe block. När den inväntade metoden blir kräver-osäker, krävs en tillfällig variabel för att hålla aktiviteten innan den kan vänta:
// Without unsafe expressions: must spill to a temporary
Task t;
// SAFETY: Discharges obligations because reasons
unsafe { t = DoWork(); }
await t;
// With unsafe expressions: the unsafe context wraps only the call;
// the await remains outside it and is fully legal
// SAFETY: Discharges obligations because reasons
await unsafe(DoWork());
Fånga filter.
when Filtret för en catch sats är ett uttryck, inte en instruktionstext. Ett unsafe block kan bara omge uttryck, så det finns ingen plats att placera en runt bara filteruttrycket. Om brödtexten try innehåller ett await uttryck kan ett unsafe block inte heller omge hela/trycatch -instruktionen –await tillåts inte i ett unsafe block. När en metod som används i ett filter blir kräver osäker är det enda alternativet utan unsafe uttryck en hjälp:
// Without unsafe expressions: must spill to a local function
static bool FilterHelper(Exception e)
{
// SAFETY: Discharges obligations because reasons
unsafe { return NowUnsafeCall(e); }
}
try
{
await DoWork(); // 'await' here prevents wrapping the whole try/catch in 'unsafe'
}
catch (Exception e) when (NowUnsafeCall(e))
{
}
// With unsafe expressions: inline and minimal scope
try
{
await DoWork();
}
// SAFETY: Discharges obligations because reasons
catch (Exception e) when (unsafe(NowUnsafeCall(e)))
{
}
Fältinitierare. Under de uppdaterade reglerna unsafe introducerar ett fält inte någon unsafe kontext i dess initialiserare. När ett fälts initierare anropar en medlem med krav på osäkert innehåll tillhandahåller ett unsafe uttryck kontexten utan att någon hjälpmetod krävs:
// Without unsafe expressions: must spill to a helper method
static int InitialValue()
{
// SAFETY: Discharges obligations because reasons
unsafe { return ReadFromPointer(); }
}
static int _value = InitialValue();
// With unsafe expressions: inline
// SAFETY: Discharges obligations because reasons
static int _value = unsafe(ReadFromPointer());
Konstruktorinitierare.
this(...) och base(...) initialiserarargumentlistor är uttryck, inte instruktionskroppar. Om ett av dessa argument anropar en medlem som kräver osäkert finns det återigen ingen plats att infoga ett unsafe block, så anropet måste annars flyttas till en hjälp:
class C(int x)
{
// SAFETY: Discharges obligations because reasons
C() : this(unsafe(GetUnsafeValue()))
{
}
}
class Derived : Base
{
// SAFETY: Discharges obligations because reasons
Derived() : base(unsafe(GetUnsafeValue()))
{
}
}
Infogade anrop. Mer allmänt håller omslutningen endast det osäkra underuttrycket granskningsomfånget tätt och undviker att hämta omgivande säker kod (till exempel argumentutvärdering eller ett innehållande metodanrop) i kontexten unsafe :
extern int Add(int i1, int i2); // Some fancy extern addition function
// Code I want to write:
// SAFETY: Discharges obligations because reasons
Console.WriteLine(unsafe(Add(1, 2)));
// Code I have to write without unsafe expressions, option 1
// (unsafe context unnecessarily includes the WriteLine call):
// SAFETY: Discharges obligations because reasons
unsafe
{
Console.WriteLine(Add(1, 2));
}
// Code I have to write without unsafe expressions, option 2
// (very verbose and harder to read):
int result;
// SAFETY: Discharges obligations because reasons
unsafe
{
result = Add(1, 2);
}
Console.WriteLine(result);
Frågor
(besvarad) Använd RequiresUnsafeAttribute för att ange medlemmar som kräver osäkra
I stället för att använda nyckelordet unsafe på medlemmen för att ange medlemmar som kräver osäkra kan vi använda ett attribut (RequiresUnsafeAttribute) som tillämpas på medlemmen (och inte ändra innebörden unsafe av modifieraren för medlemmar).
unsafeFördelar med :
- liknande andra språk och därmed lättare att förstå,
- mer identifierbar än ett attribut.
Fördelar med ett attribut (eller ett annat nyckelord):
- undviker att bryta befintliga medlemmar som har markerats som
unsafe, - inkrementell implementering möjlig (medlem för medlem),
- inte framtvingar märkning av hela kroppen som
unsafe(även medunsafenyckelord kan vi ändraunsafeför att inte ha en effekt på kroppar dock), - tillåter att du utelämnar alla fel som kräver osäkra fel utan att själva medlemmen behöver markeras som kräver osäker (exempel).
Diskussioner:
- LDM 2025-11-12: använd nyckelord
- LDM 2026-01-26: använd attribut
- LDM 2026-04-06: använd nyckelord
Svar: Använd nyckelord unsafe för att ange medlemmar som kräver osäkra .
Säkra kontexter för lokala funktioner/lambda
Just nu unsafe är en metodtext lexikalt begränsad. Alla kapslade lokala funktioner eller lambdas ärver detta, och deras kroppar är i ett minnessäkert sammanhang.
Är det här beteendet som vi vill behålla på språket?
Observera att om vi behåller unsafe som den modifierare som används för att exponera att anroparen måste vara osäker kan detta påverka metodens signatur.
Som det för närvarande föreslås behåller inte kapslade anonyma och lokala funktioner den osäkra kontexten för deras innehållande medlem.
Ombudstyp unsafety
Vi kan tillåta märkning av ombudstyper och lambdas (och funktionstyper) som kräver osäker.
Detta skulle kräva flera ytterligare regler (utanför unsafe kontexten):
- inte tillåta användning av icke-osäkra ombud som typargument,
- tillåt inte att konvertera dessa ombud till något som inte kräver osäkra (
Delegate,Expression, ochobject), Utan detta finns det en risk för att tvingaunsafeanteckningar på fel plats och ha ett område där det verkliga områdetunsafety inte är korrekt framhävt.
Lambda/metodgruppkonvertering till säkra ombudstyper
Om vi tillåter unsafe lambdas och ombud, bör konvertering av en lambda eller metodgrupp som kräver osäkert värde konverteras till en icke-kräver-osäker delegattyp som tillåts utan varning eller fel i en unsafe kontext? Om vi inte gör det kan det vara ganska smärtsamt för olika delar av ekosystemet, särskilt eventuella uppräkningar som skickas via LINQ-frågor.
Lambda/metodgruppens naturliga typer
I dag är den enda verkliga effekten på semantik och kodgen (förutom ytterligare metadata) att ändra function_type för en lambda- eller metodgrupp när unsafe den finns i signaturen. Om vi skulle undvika att göra detta skulle det inte heller finnas någon verklig inverkan på någon av dem, vilket skulle kunna ge adoptörerna mer förtroende för att beteendet inte subtilt har förändrats under huven.
Note
Om vi bestämmer oss för att behålla möjligheten att ha unsafe lambdas måste vi uppdatera det här förslaget så att det inkluderar en syntaxändring så att lambdas kan deklareras unsafe från början.
Pekare till hanterade typer
C# 11 tillåter pekare till hanterade typer med en varning.
Ska vi lätta på varningen för åtgärdsadresser?
Vi tror att problemet bara är när användaren avrefereras sådan pekare, som faller under normala osäkra utvecklingsregler.
Men hur är det sizeofmed ?
stackalloc som initierad
I dag betraktar stackallocspecifikationen alltid minnet som onitialiserat och säger att innehållet är odefinierat om det inte rensas eller tilldelas manuellt. Anser vi att det här är en specifikationsbuggar, eller behöver vi ändra vad vi anser unsafe i stackalloc syfte?
stackalloc Regel
LDM bör bekräfta regelnstackalloc som definierats ovan och om den ska tillämpas oavsett anmälning som andra pekarrelaterade ändringar.
AllowUnsafeBlocks
Innebörden av AllowUnsafeBlocks är för närvarande oförändrad – den måste anges till true för att kunna använda nyckelordet unsafe eller SkipLocalsInitAttribute.
Ska vi inte kräva det SkipLocalsInitAttribute enligt de uppdaterade reglerna eftersom BCL kan markera det attributet som kräver osäkert?
Ska vi kräva det för nyckelordet safe också?
Ska vi kräva det för både unsafe block och unsafe medlemsdeklarationer eller någon annan kombination av dessa?
(besvarad) unsafe Uttryck
Andra språk med mer omfattande unsafe funktioner har lagts till unsafe som ett uttryck som förbättrar användarens ergonomi och gör det möjligt för författare att mer exakt begränsa var unsafe som används. Är detta något som vi vill ha i C#? Överväg ett infogat anrop till en unsafe medlem som hanterar säkerheten direkt: just nu skulle författaren antingen behöva omsluta hela -instruktionen i ett unsafe block, utöka kontextens unsafe omfattning, eller så skulle de behöva dela upp det inre funktionsanropet till en mellanliggande variabel.
extern int Add(int i1, int i2); // Some fancy extern addition function
// Code I want to write:
Console.WriteLine(unsafe(Add(1, 2)));
// Code I have to write option 1, unsafe context unnecessary includes the WriteLine call
unsafe
{
Console.WriteLine(Add(1, 2));
}
// Code I have to write option 2, very verbose and harder to read:
int result;
unsafe
{
result = Add(1, 2);
}
Console.WriteLine(result);
Svar: Ja. Se det detaljerade designavsnittet.
Fler unsafe kontexter och avkopplingar
Ska vi lätta på fler begränsningar kring unsafe och pekarparametrar i iteratorer och asynkrona metoder?
Särskilt att tillåta await UnsafeMethod() skulle vara användbart eftersom användarna nu måste skriva om det till Task t; unsafe { t = UnsafeMethod(); } await t;.
Mer information finns i referens/osäker i iteratorer/asynkronisering .
Bör vi också tillåta &UnsafeMethod i ett säkert sammanhang? I dag som förslaget ser ut kräver unsafe detta kontext om metoden är markerad som unsafe.
Men eftersom vi bara hämtar dess adress, som behöver unsafe kontext när dereferenced/anropas, kan vi tillåta själva adressen i en säker kontext.
-
LDM 2026-05-27:
awaitiunsafebehov av ett konkret förslag
Osäkra avkopplingar gated på LangVersion
Ska vi göra de osäkra kontextavslappningarna ovillkorliga för LangVersion?
- LDM 2026-04-06: de är inte villkorade av minnessäkerhetsregler
- TODO: Hur är det med LangVersion?
(besvarad) unsafe på typer
Vi kan överväga att inte automatiskt göra hela den lexikala omfattningen av en unsafe typ till en unsafe kontext och varna för en unsafe på en typ eftersom det inte skulle ha någon betydelse.
-
LDM 2025-11-12:
unsafepå en typ har ingen betydelse - LDM 2026-05-13: det blir ett fel (kan ses över baserat på feedback)
Svar: unsafe på en typ är ett fel (kan ses över baserat på feedback) enligt de uppdaterade reglerna.
unsafe på accessorer
Vi har nyligen aktiverat unsafe egenskapsåtkomster men inte på händelseåtkomster, i linje med andra befintliga modifierare.
Det innebär också att unsafe på en egenskap är bara en genväg för unsafe på dess accessorer.
Men samtidigt partialkräver unsafe s att modifierarna matchar:
partial class C
{
unsafe partial int P { get; set; } // effectively both `get` and `set` are `unsafe` here
unsafe partial int P { unsafe get => 0; set { } } // still an error: `unsafe` on `get` doesn't match
}
// similar to this pre-existing behavior:
unsafe partial class D
{
unsafe partial void M();
}
unsafe partial class D
{
partial void M() { } // error about missing `unsafe`
}
Kanske bör den bete sig på samma sätt som readonly, dvs. inte tillåta unsafe både egenskapen och dess accessor på samma gång:
partial struct S
{
readonly partial int P { get; set; }
// error: Both partial member declarations must be readonly or neither may be readonly
partial int P { readonly get => 0; set { } }
// error: Cannot specify 'readonly' modifiers on both property or indexer 'S.P2' and its accessor. Remove one of them.
readonly int P2 { readonly get => 0; set { } }
}
(besvarad) Tillåt att fel som kräver osäkra fel utelämnas i scenarier med gränsfall
Hur ska vi tillåta att fel som kräver osäkra fel utelämnas i följande scenarier?
class A : System.Attribute
{
unsafe public A() { } // declaring requires-unsafe constructor
}
class C
{
[A] public void M() { } // error: applying requires-unsafe `A..ctor`
}
class B : A
{
public B() { } // error: calling requires-unsafe `A..ctor` (implicit `: base()`)
}
class X<T> where T : new();
class D
{
public void M(X<A> x) { } // error: using `X` which uses requires-unsafe `A..ctor`
}
För att förhindra fel som kräver osäkert måste vi på något sätt införa en unsafe kontext i signaturen för dessa medlemmar.
Men nyckelordet unsafe introducerar inte någon unsafe kontext längre.
Vi skulle kunna införa unsafe en unsafe kontext i signaturen, men det verkar olyckligt att tvinga en konstruktor att göra en konstruktor osäker när man vill anropa en bas som kräver osäker konstruktor.
Vi kan göra användningar som kräver osäker användning i signaturer varningar som användarna kan undertrycka på plats om de träffar dessa sällsynta kantfall.
Det finns ett liknande problem med typer eftersom unsafe de inte heller introducerar unsafe kontext:
class A : Attribute
{
unsafe public A() { } // declaring requires-unsafe constructor
}
[A] class C; // error: applying requires-unsafe `A..ctor`
class B() : A(); // error: calling requires-unsafe `A..ctor`
class X<T> where T : new();
class D : X<A>; // error: inheriting from `X` which uses requires-unsafe `A..ctor`
-
LDM 2026-05-13:
- Icke-körbar kod, till exempel attributprogram, bör förbli ett oövertryckligt fel (tills vi hör feedback)
- andra kantfall som
new()kan förbli ett fel tills vi hör feedback - tillåt inte deklarering av parameterlösa kräver osäkra konstruktorer
- endast en
unsafekonstruktors initiator kan anropa en kräver osäkerbaseellerthiskonstruktor
params samlingar
class C
{
unsafe public C() { } // declaring requires-unsafe constructor
}
class B
{
public void M(params C c) { }
}
Den här deklarationen kan bara tillåtas eftersom anrop av den här metoden kräver en unsafe kontext ändå eftersom den osäkra params samlingen skapas på anropsplatsen.
Även om det gör deklarationen i praktiken kräver osäker, så vi kan bara kräva anteckningen unsafe eller åtminstone varna för detta faktum.
Observera att samlingsfallet params i dag är ett fel i linje med hur andra liknande funktioner fungerar här (Obsolete, UnmanagedCallersOnly), men det kan vara en implementeringsfel.
Välkända medlemmar
För enkelhetens skull och förstånds skull föreslår vi att kompilatorn kan anta att alla välkända medlemmar (till exempel Array.Length) kan antas vara säkra (dvs. inte kräver osäkra).
Xml-dokument
Att överföra en skyldighet till uppringare medför ett ansvar att klargöra vad denna skyldighet är. Ska vi formalisera detta utöver vad som redan kan representeras i XML-dokument?
Medlemmar som har markerats unsafe bör ha kommentarer som anger vad som krävs för att anroparen ska kunna göra så att koden är korrekt.
För att göra det enklare att se och göra det enklare att skilja i dokumentationen skulle en ny XML-dokumenttagg vara till hjälp: <safety />.
Det kan förväntas att alla för-/eftervillkor skulle placeras i <safety> blockering.
För att dokumentera resonemang för varje unsafe block rekommenderar vi att du använder // SAFETY kommentarer som liknar Rust.
Ska vi också kontrollera dessa av kompilatorn (t.ex. ha en varning som inte är standard) eller lämna den till en analysator?
- LDM 2026-05-27: inget konkret beslut
Fler meningslösa unsafe varningar
Bör fler deklarationer generera den meningslösa unsafe varningen eller felet?
Till exempel metoder med tomma kroppar (eller extern), osv. Vi har redan en IDE-analysator för onödiga unsafe .
Bör [ModuleInitializer] unsafe void M() { } vara ett fel, på samma sätt som en statisk konstruktor?
(besvarad) unsafe Fält
I dag läggs inget förslag fram unsafe på ett fält. Vi kan dock behöva lägga till det, så att alla läsningar från eller skrivning till ett fält som har markerats som unsafe måste vara i en unsafe kontext. Detta skulle göra det möjligt för oss att bättre kommentera oron kring kod, till exempel:
class SafeWrapper
{
internal byte* _p;
public void DoStuff()
{
unsafe
{
// ... validate that the object state is good ...
// ... perform operation with _p ....
}
}
}
// Elsewhere in safe code:
void M(SafeWrapper w)
{
w._p = stackalloc byte[10];
}
Ska vi också markera autoegenskapens bakgrundsfält som unsafe?
För att vara konsekvent med vårt beslut för medlemmar skulle det vara bra att göra unsafe på ett fält inte heller införa ett unsafe sammanhang.
Om kräver osäkra åtgärder används i fältets initiering kan användaren alltid kapsla in dem i en metod, eller så kan vi introducera unsafe uttryck.
-
LDM 2026-05-13: fält kan markeras som kräver osäkert via
unsafe; initierarna finns inte iunsafekontexten.
(besvarad) Explicit layout
Ska fält i structs markeras som [StructLayout(Explicit)] eller [ExtendedLayout] måste markeras som unsafe?
Rekommendation: Ja.
-
LDM 2026-05-13: ja, kräv antingen
unsafeellersafe, precis som förexterns.
Explicit layout och bakgrundsfält
Om kompilatorn syntetiserar ett bakgrundsfält för en autoegenskap eller fältliknande händelse i en Explicit/Extended typ, bör vi då kräva safe/unsafe egenskapen/händelsen i stället?
Annars skulle användaren tvingas expandera dessa automatiska deklarationer till ett manuellt fält plus medlemsdeklarationer för wrapper.
Hur är det med en primär konstruktorparameter som hämtar ett bakgrundsfält?
Både safe och unsafe modifieraren tillåts för närvarande inte för en parameterdeklaration.
[Out] och [SkipLocalsInit]
Eftersom VB till exempel inte garanterar att [Out] parametrar initieras kan [SkipLocalsInit]anrop av sådana parametrar övervägas unsafe i C#.
Å andra sidan känns det som samtalsmottagarens problem att det inte upprätthåller sitt [Out] kontrakt (på samma sätt kan det vara osäkert på många andra sätt).
Om vi beslutar att dessa fall ska vara unsafekan vi utesluta metoder som vi vet har valt (för närvarande är de från C# som garanterar korrekt användning av [Out] men om andra språk implementerar de nya reglerna bör de också garantera det).
Ta adressen till en ennitialiserad variabel
I dag kan det vara bra att ta adressen till en inte definitivt tilldelad variabel med den variabeln som definitivt tilldelas, vilket exponerar eninitierad medlem. Vi har ett par alternativ för att lösa detta:
- Kräv att variabler definitivt tilldelas innan du tillåter att en adressoperator används på dem.
- Gör det osäkert att ta adressen till en onitialiserad variabel.
Examples:
static void SkipInit<T>(out T value)
{
// value is considered definitely assigned after the address-of
fixed (void* ptr = &value);
}
int i;
// i is considered definitely assigned after the address-of
_ = &i;
// Incrementing whatever was on the stack
i++;
Värdet för MemorySafetyRulesAttribute
Vad ska vara den "aktiverade"/"uppdaterade" versionen av minnessäkerhetsregler?
2?
15?
11?
Se även SDK Osäker implementering och Mer gradvis opt-in?.
(besvarad) Mer gradvis opt-in?
I dag kan du välja två saker samtidigt: att tillämpa de osäkra reglerna i din egen kod och en signal som publiceras till dina konsumenter (via ett attribut på sammansättningsnivå) om att dina anteckningar är avsiktliga. Det kan finnas användare som vill börja hämta tvingande diagnostik när de kommenterar, utan att vara redo att publicera att de helt har kommenterat sin sammansättning. Ska vi ha en "mitt"-opt-in-nivå som skulle visa den osäkra diagnostiken som varningar, och det fullständiga anmälningsmeddelandet skulle höja dem till fel?
- LDM 2026-04-29: Ja, men det blockerar inte för förhandsversion
(besvarad) Finare detaljerad opt-in
Tillhandahåller du en detaljerad, regionbaserad opt-in-mekanism som motsvarar den som vi har skapat för null-referenstyper, där användarna kan använda direktiv för att aktivera funktionen för specifika regioner med källkod? Se även Anmäl dig för kodregioner.
- LDM 2026-04-29: nej
(besvarad) extern implicit osäker
Det här är för närvarande den enda plats där RequiresUnsafeAttribute syntetiseras utan ett explicit unsafe nyckelord.
Är det okej med den här avvikare?
Dessutom exponerar CoreLib många externa metoder (FCalls) som säkra idag. Om externa metoder behandlas som implicit osäkra måste de implicit osäkra externa metoderna omslutas med en säker omslutning. Vi kan stöta på situationer där det är svårt att lägga till den extra omslutningen på grund av körningsimplementeringsinformation.
-
LDM 2026-04-01:
externMedlemmar bör uttryckligen markeras som säkra eller osäkra - LDM 2026-04-06: samma beslut upprepades
-
LDM 2026-04-13: tillfälligt beslut att använda
safenyckelord -
LDM 2026-05-13: använd
safenyckelord (fortfarande öppet för återbesök dock)
Svar: extern medlemmar måste markeras antingen unsafe eller safe (vi lägger till ett nytt nyckelord för det, men kan gå tillbaka till det innan funktionen levereras, baserat på feedback).
(besvarad) unsafe kontextstandarder i medlemmar
Vi kan överväga att inte automatiskt göra hela brödtexten i en unsafe metod till en unsafe kontext. Rust gjorde detta i RFC 2585, med motiveringen att det hjälper till att minska omfattningen av unsafe block till de platser där unsafe faktiskt används. Vi kan göra samma sak i C#, antingen som en varning eller ett fel, med liknande motiveringar.
-
LDM 2026-04-22: Ja,
unsafei signaturen gör inte brödtextenunsafe
(besvarad) new() Begränsning
Vill vi stödja new() med kravsäkra (något som vi för närvarande inte verkar ha stöd för i kompilatorn för andra funktioner, till exempel Obsolete)?
M<C>(); // should be an error outside `unsafe` context since `M` calls the requires-unsafe `C..ctor`?
void M<T>() where T : new()
{
_ = new T();
}
class C
{
unsafe public C() { }
}
-
LDM 2026-05-13: typer med kravsäkra parameterlösa konstruktorer bör inte uppfylla villkoret
new()
new() begränsning och usings
Hur bör den bete sig i alias och statiska användningar?
- Om det skulle vara ett fel i deklarationen
using, undertryckbart via nyckelordetunsafesom vi redan stöder där, eller - bör det vara ett fel normalt på användningsplatsen som det skulle vara om det skulle användas direkt utan ett alias eller statisk användning?
Note
I det andra fallet skulle vi behöva lägga till en "meningslös unsafe" varning för användning av alias och statiska användningar.
class C
{
unsafe public C() { }
}
class D<T> where T : new()
{
public static void M() { _ = new T(); }
}
using X = D<C>;
using unsafe X = D<C>;
X.M();
using static D<C>;
using static unsafe D<C>;
M();
Observera att andra begränsningar fungerar som det tidigare alternativet i dag:
using X = D<C>; // error here
_ = new X(); // ok
_ = new D<C>(); // error here
class C
{
public C(int x) { }
}
class D<T> where T : new();
Bör fler konstruktioner vara unsafe?
-
dynamic(bör förmodligen matcha vad BCL bestämmer för reflektions-API:er)
(besvarad) Hur bryta vill vi skeva
Frågetext
Det ursprungliga förslaget är ett maximalt banbrytande tillvägagångssätt, främst som ett lackmustest för hur aggressiva vi vill vara. Det föreslår ingen möjlighet att välja in/ut delar av koden, ändrar innebörden av unsafe på metoder, förbjuder användning av unsafe på typer, använder fel i stället för varningar och tvingar i allmänhet migreringen att ske på en gång, vid den tidpunkt då kompilatorn uppgraderas (och sedan potentiellt upprepade gånger som beroenden uppdateras och läggs unsafe till medlemmar som redan användes). Vi har dock en mängd erfarenhet av att göra ändringar som denna som vi kan använda för att begränsa storleken på delningen och tillåta inkrementell implementering. De här alternativen beskrivs nedan.
Anmäl dig till kodregioner
Det här är inte första gången som C# har omdefinierat "bas"-fallet med oanvänd kod. C# 8.0 introducerade den nullbara referenstypsfunktionen, som på många sätt kan ses som en skiss för hur unsafe funktionen utformas. Det hade liknande mål (förhindra buggar som kostar miljarder dollar genom att omdefiniera hur standard C# tolkas) och en liknande allmän funktionsuppsättning (lägg till ny information i typer för att sprida tillstånd och undvika buggar). Det var också starkt banbrytande och behövde en stark uppsättning opt-in- och opt-out-funktioner för att tillåta att funktionen antas över tid av kodbaser. Den funktionen är den "nullbara referenstypkontexten". Det här är ett lexikalt omfång som informerar kompilatorn för en viss region i kod, både hur man tolkar referenser av oanmäld typ och vilka typer av varningar som ska ges till användaren. Vi kan också använda detta som en modell för, lägga till en "säkerhetsregelkontext" eller liknande för unsafe att kontrollera om dessa nya regler tillämpas eller inte.
En fördel med de nya unsafe funktionerna är att de är mycket mindre vanliga. Det finns ett anständigt antal unsafe anrop i de översta biblioteken, men våra gissningar om procentandelen av de översta biblioteken som använder unsafe är mycket lägre än "varje enskild rad med C#-kod som någonsin skrivits". Förhoppningsvis innebär detta att även om vissa möjligheter att välja in/ut eventuellt behövs, behöver vi inte en så komplicerad mekanism som nullable har, med dedikerade preprocessor-växlar och liknande.
Varningar kontra fel
I förslaget anges för närvarande att minnessäkerhetskraven för närvarande tillämpas via en varning snarare än ett fel. Detta bygger på vår erfarenhet av att arbeta med den nullbara funktionen, där varningar tillät kodbaser att stegvis anta den nya funktionen och inte behöver konvertera stora mängder kod på en gång. Vi förväntar oss att en liknande process kommer att behövas för osäkra varningar: många kodbaser kommer helt enkelt att kunna slå på de nya reglerna globalt och gå vidare med sina liv. Men vi förväntar oss att de kodbaser som vi bryr oss mest om att anta de nya reglerna kommer att ha stora mängder kod att kommentera, och vi vill att de ska kunna gå vidare med funktionen, snarare än att se en vägg av fel och ge upp omedelbart. Genom att utfärda kravvarningar tillåter vi att dessa kodbaser åtgärdar varningar fil för fil eller metod för metod efter behov, vilket inaktiverar varningarna överallt annars.
Metodsignatursbrytningar
Just nu föreslår vi att unsafe som ett nyckelord på metoden flyttas från något som är lexikalt omfångsbegränsat utan semantisk inverkan till något som har semantisk inverkan och inte är lexikalt begränsad.
Vi kan begränsa den här pausen genom att införa ett nytt nyckelord för när anroparen för en metod eller medlem måste vara i ett unsafe sammanhang, callerunsafe till exempel som en modifierare.
Standardvärden för källgeneratorer
För nullable tvingar vi generatorförfattare att uttryckligen välja nullable oavsett om hela projektet har valt funktionen som standard, så att generatorutdata inte bryts av att användaren aktiverar null och varnar som fel. Ska vi göra samma sak för källgeneratorer?
Conclusion
Besvaras i LDM 2025-11-05. Vi rapporterar fel för minnessäkerhetsproblem när de nya reglerna aktiveras och inga undantag görs för källgeneratorer.
(besvarad) Fel eller varningar?
- LDM 2025-11-05: fel
(besvarad) Källa generator affordance
- LDM 2025-11-05: ingen
(besvarad) Vill du kräva safe maker för medlemmar med unsafe block eller pekare?
- LDM 2026-04-13: nej
(besvarad) Kompatibilitetsläge för icke-anmälda uppringare också?
- LDM 2026-04-22: ja
- LDM 2026-04-29: ingen ändring för anmälda
- LDM 2026-04-29: allvarlighetsgrad: fel
Svar: icke-anmälda medlemmar med pekare i signatur anses vara kravsäkra för inaktiva uppringare.
(besvarad) Vill du utöka kompatibilitetsläget?
Ska vi överväga nint och System.IntPtr som pekare också?
Bör vi betrakta extern/DllImport från icke-anmälda som kräver osäkra också?
Bör vi ha en allmän varning när en anmäld sammansättning refererar till en icke-anmäld sammansättning?
- LDM 2026-04-29: inga tillägg (analysverktyg kan täcka vissa mindre säkra osäkra signaler)
C# feature specifications