C standardı, boş işaretçilerin makinenin sıfır adresinde olmasını gerektirmez. ANCAK, 0bir işaretçi değerine bir sabit değer NULLatamak bir işaretçi (§6.3.2.3 / 3) ile sonuçlanmalı ve boş göstericiyi bir boolean olarak değerlendirmek yanlış olmalıdır. Bu gerçekten eğer biraz garip olabilir do sıfır adresi istiyor ve NULLsıfır adresi değil.
Bununla birlikte, derleyicide ve standart kitaplıkta (ağır) değişiklikler yapıldığında NULL, standart kitaplığa tam anlamıyla uyumlu kalırken alternatif bir bit örüntüsü ile temsil edilmek imkansız değildir . Öyle değil sadece tanımını değiştirmek için yeterli NULLsonra da, ancak kendisi NULLgerçek olarak değerlendirilir.
Özellikle şunları yapmanız gerekir:
- Atamalarda işaretçiler (veya işaretçiler için atmalar) gibi başka bir sihirli değere dönüştürülecek sıfırları düzenleyin
-1.
0Bunun yerine sihirli değeri kontrol etmek için işaretçiler ve sabit bir tam sayı arasında eşitlik testleri düzenleyin (§6.5.9 / 6)
- Sıfır için kontrol etmek yerine sihirli değere eşitliği kontrol etmek için bir işaretçi türünün boole olarak değerlendirildiği tüm bağlamları düzenleyin. Bu eşitlik testi anlambiliminden kaynaklanır, ancak derleyici bunu dahili olarak farklı şekilde uygulayabilir. Bkz. §6.5.13 / 3, §6.5.14 / 3, §6.5.15 / 4, §6.5.3.3 / 5, §6.8.4.1 / 2, §6.8.5 / 4
- Caf'in belirttiği gibi, yeni boş gösterici temsilini yansıtmak için statik nesnelerin (§6.7.8 / 10) ve kısmi bileşik başlatıcıların (§6.7.8 / 21) başlatılması için anlambilimini güncelleyin.
- Gerçek sıfır adresine erişmek için alternatif bir yol oluşturun.
Halletmeniz gerekmeyen bazı şeyler var. Örneğin:
int x = 0;
void *p = (void*)x;
Bundan sonra pboş gösterici olacağı garanti EDİLMEZ. Yalnızca sabit atamaların ele alınması gerekir (bu, gerçek sıfır adresine erişmek için iyi bir yaklaşımdır). Aynı şekilde:
int x = 0;
assert(x == (void*)0); // CAN BE FALSE
Ayrıca:
void *p = NULL;
int x = (int)p;
xolması garanti edilmez 0.
Kısacası, bu koşul görünüşe göre C dili komitesi tarafından değerlendirildi ve NULL için alternatif bir temsil seçecek olanlar için değerlendirmeler yapıldı. Şimdi yapmanız gereken tek şey, derleyicinizde büyük değişiklikler yapmak ve hey, işiniz bitti :)
Bir yan not olarak, bu değişiklikleri derleyici uygun olmadan önce bir kaynak kodu dönüştürme aşaması ile uygulamak mümkün olabilir. Yani, önişlemci -> derleyici -> assembler -> bağlayıcının normal akışı yerine, bir önişlemci -> NULL dönüşüm -> derleyici -> assembler -> bağlayıcı eklersiniz. O zaman aşağıdaki gibi dönüşümler yapabilirsiniz:
p = 0;
if (p) { ... }
/* becomes */
p = (void*)-1;
if ((void*)(p) != (void*)(-1)) { ... }
Bu, tam bir C ayrıştırıcısının yanı sıra, bir tür ayrıştırıcısı ve hangi tanımlayıcıların işaretleyicilere karşılık geldiğini belirlemek için tiplerin ve değişken bildirimlerinin analizini gerektirir. Ancak, bunu yaparak, derleyicinin kod oluşturma bölümlerinde uygun şekilde değişiklik yapmak zorunda kalmazsınız. clang bunu uygulamak için yararlı olabilir - bunun gibi dönüşümler düşünülerek tasarlandığını anlıyorum. Elbette standart kitaplıkta da değişiklik yapmanız gerekebilir.
mprotectgüvenliğini sağlayabileceğiniz adresler olacaktır . Veya platformda ASLR veya benzeri yoksa, platformun fiziksel belleğinin ötesinde adresler. İyi şanslar.