0000000C adresi özel bir adres midir?


32

Programlarken bazen işler bozulur. Bir hata yaptınız ve programınız yanlış bir adresten okumaya çalışıyor.

Bu istisnaların sıkça olduğu gibi bana dikkat çeken bir şey:

Access violation at address 012D37BC in module 'myprog.exe'. Read of address 0000000C.

Şimdi birçok hata günlüğü görüyorum ve bana göre en dikkat çeken şey: 0000000C. Bu "özel" bir adres mi? Kötü okumalara sahip diğer erişim ihlallerini görüyorum ama adresler rastgele görünüyor, ancak bu tamamen farklı durumlarda geri gelmeye devam ediyor.


1
Ben de fark ettik 0000000Colduğu yolu daha yaygın 00000008, ancak cevapların hiçbiri adresine görünüyor hiç: /
mölemeye Ördek

2
Belki de bu System.Runtime.CompilerServices.RuntimeHelpers.OffsetToStringData, 12=0x0Cbu dengelemenin daha yaygın olmasının bir nedenidir.
Mark Hurd,

1
@MarkHurd Bu korkutucu. Gerçekten, bunun büyük bir erişim ihlali kaynağı olacak. NET dizelerini okumak / yazmak için yönetilmeyen birçok uygulama olduğunu düşünüyor musunuz?
Ocak'ta Luaan

Yanıtlar:


57

00000000özel bir adres (boş işaretçi). 0000000Cboş göstericiye 12 ofset eklediğinizde elde ettiğiniz şeydir, çünkü büyük olasılıkla birisi zaşağıdaki gibi bir yapının üyesini gerçekte boş olan bir gösterici ile almaya çalıştı .

struct Foo {
    int w, x, y; // or anything else that takes 12 bytes including padding
    // such as: uint64_t w; char x;
    // or: void *w; char padding[8];
    // all assuming an ordinary 32 bit x86 system
    int z;
}

29
Veya belki de küçük bir integral değer yanlışlıkla bir işaretçimiş gibi geçersiz kılınmıştır. Küçük değerler, büyük değerlerden çok daha yaygındır, bu nedenle, örneğin 0x43FCC893 yerine 0X0000000C gibi yasadışı adresler oluşturma eğilimindedir.
Kilian Foth

3
Bu soruyu sormamın nedeni, 0000000C'nin diğer adreslerle karşılaştırıldığında çok sık geri dönmesidir. 12 dengesi neden 4, 8 veya 16 değerinden daha büyüktür?
Pieter B

5
Daha fazla araştırmadan sonra bu cevap tamamen doğru. Kaynağımda sınıfların "tag" özelliği yoğun olarak kullanılıyor (iyi ya da kötü, bununla başa çıkmak zorundayım.) Benim durumumdaki tag özelliği, düşük seviyeli bir temel sınıfın bir parçası ve her zaman bu dengelemede yaratıldı.
Pieter B

1
Mükemmel nokta Belki de boş gösterici kılıfı ele alınmıştı, fakat boş gösterici ++ sadece normal (ve bu durumda geçersiz) bir adres, bu yüzden sadece erişildikten sonra başarısız oluyor.
Neil

8
@Leushenko Evet, bellek koruması genellikle tüm sayfalarda çalışır ve yalnızca 0 yakalamak mümkün olsa bile, aşağıdaki adresleri de korumanız önerilir, çünkü boş bir göstergeyle işaretçi aritmetik olması durumunda erişilmesi muhtemeldir (çünkü OP davası).

11

Windows bu KQUEUE yasa dışıdır tüm ilk ve son sayfayı başka bir deyişle, süreç belleğin ilk veya son 64 KiB (aralıkları 0x00000000için 0x0000ffffve 0xffff0000için 0xffffffff32-bit uygulamasında).

Bu, bir boş gösterici ya da dizini boşa çıkarmanın tanımsız davranışını boş bir diziye hapsetmektir. Sayfa boyutu 64 KiB olduğundan, Windows'un yalnızca ilk veya son sayfaya geçerli bir aralık atanmasını engellemesi gerekir.

Bu, (geçerli adresler dahil) herhangi bir değeri olabilecek başlatılmamış işaretçilere karşı korunmaz.


7
Windows bunu gerçekten yapamaz. Sayfa tablosu, x86 tarafından tanımlanan ve istenen bir yapıdır ve küçük sayfalar 4 KB'de sabitlenmiştir. Taştan yapılmıştır (daha doğrusu silikonda). 64KB büyük olasılıkla kolaylık sağlamak içindir.
ElderBug

12
İki boyutun gücü önemli olduğundan, bu durumda 65 kB yerine 64 KiB yazmayı tercih ederim.
KodlarInChaos

4
64KB aralığı, NT'nin Aplha sürümünden geriye kaldı. Ve sayfa boyutu değil, tahsisat ayrıntı düzeyidir. blogs.msdn.com/b/oldnewthing/archive/2003/10/08/55239.aspx
shf301

3
@CodesInChaos: "M", "G" ve "T" nin büyük harfleri belirsiz olsa da, 10 ^ 3 için "k" ve 2 ^ 10 için "K" kullanımından vazgeçmek için bir neden göremiyorum.
supercat,

2
@MooingDuck Evet, gerçekten de bu yüzden küçük sayfalara yer verdim. Çoğu x64 CPU, 1GiB sayfalarını da destekler. Bildiğim kadarıyla, Windows özel API'lerle tahsis edilmedikçe, her zaman 4KB sayfalı sayfalar.
ElderBug

2

Neden 0x0Cdaha yaygın göründüğü gibi 0x08(gerçekten mi? Bilmiyorum; ve ne tür uygulamalarda?) Bunun sanal yöntem tablosu işaretçileriyle ilgisi olabilir. Bu gerçekten bir yorum (vahşi kütle tahminde :), ama biraz daha büyük, işte böyle 0x04. Örneğin, başka bir sanal sınıftan miras alan bir sınıf şöyle bir bellek düzenine sahip olabilir:

0x00 - VMT pointer for parent
0x04 - Field 1 in parent
0x08 - VMT pointer for child
0x0C - Field 1 in child

Bu ortak bir senaryo mu, hatta yakın mı? Emin değilim. Bununla birlikte, 64 bitlik bir uygulamada bunun daha da ilginç bir şekilde 0x0Cdeğere kaymasının olabileceğini unutmayın :

0x00 - VMT parent
0x08 - Field 1 parent
0x0C - VMT child
0x14 - Field 2 child

Bu yüzden aslında boş göstergelerdeki ofsetlerde uygulamaların önemli örtüşme olabileceği bir çok durum var. Bu, bir alt sınıftaki ilk alan veya sanal yöntem tablosu işaretçisi olabilir - bir örnekte herhangi bir sanal yöntemi çağırdığınızda gerekli, böylece bir nullişaretçi üzerinde sanal bir yöntem çağırıyorsanız , erişim ihlali alırsınız. VMT ofseti. Bu özel değerin yaygınlığı daha sonra benzer bir kalıtım düzenine sahip bir sınıf veya belirli bir arayüz (DirectX oyunları gibi bazı uygulama sınıfları için oldukça mümkün) olan belirli bir arayüz sağlayan bazı ortak API ile ilgili olabilir. Bunun gibi bazı basit ortak nedenleri takip etmek mümkün olabilir, ancak oldukça hızlı bir şekilde değişiklik yapmayan uygulamalardan kurtulma eğilimindeyim, bu yüzden ...


1
Yorumlara bakarsanız, tahminleri önemli ölçüde azaltabilirsiniz.
Deduplicator

@Deduplicator Peki, yönetilen .NET dizelerinin güvenli olmayan kodda elle işaretçi işlemleri korkutucu olarak kullanıldığı fikrini ve bunun erişim ihlallerinin daha da önemli bir nedeni olacağı fikrini buldum. “Evet, bu tamamen güvenli bir bellektir, endişelenmeyin, C # kullandık. Belleği yalnızca C ++ ile değiştirdik, ama C # ile güvenli.”
Luaan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.