Tek tek hata - Off-by-one error
Bir kapalı-tek hata ya da kapalı-bir hata (Kısaltmalar bilinen OBOE , OBO'dan , OB1 ve OBOB ) a, mantık hatası bir ayrık eşdeğer kapsayan sınır koşulu . Bilgisayar programlamasında , yinelemeli bir döngü bir kez çok fazla veya çok az yinelendiğinde ortaya çıkar . Bu sorun, bir programcı bir karşılaştırmada "küçüktür" ifadesinin kullanılması gereken yerde "küçüktür veya eşittir" kullanmak gibi hatalar yaptığında veya bir dizinin bir yerine sıfırdan başladığını hesaba katmadığında ortaya çıkabilir ( birçok dilde dizi indekslerinde olduğu gibi). Bu aynı zamanda matematiksel bir bağlamda da ortaya çıkabilir .
Diziler üzerinde döngü
Bir dizi öğe düşünün ve m ila n (dahil) arasındaki öğeler işlenecek. Kaç tane eşya var? Sezgisel bir cevap n - m olabilir , ancak bu bir farkla kapalıdır ve bir çit direği hatası sergiler ; doğru cevap ( n – m ) + 1.
Bu nedenle, hesaplamadaki aralıklar genellikle yarı açık aralıklarla temsil edilir ; kadar olan aralığın m için n (dahil) ila ile temsil edilir m (ikisi de dahil) , n + 1 (hariç) önlemek için fencepost hataları. Örneğin, beş kez yinelenen bir döngü (0'dan 4'e kadar) 0'dan 5'e yarı açık bir aralık olarak yazılabilir:
for (index = 0; index < 5; index++)
{
/* Body of the loop */
}
Döngü gövdesi, her şeyden önce, 0'a eşit indeks ile yürütülür ; index daha sonra art arda yinelemelerde 1, 2, 3 ve son olarak 4 olur. Bu noktada indeks 5 olur, dolayısıyla indeks < 5 false olur ve döngü biter. Ancak, kullanılan karşılaştırma < or = (küçük veya eşit) olsaydı, döngü altı kez yürütülürdü: index 0, 1, 2, 3, 4 ve 5 değerlerini alır. Benzer şekilde, index 1 olarak başlatılırsa. 0'dan sonra yalnızca dört yineleme olacaktır: index 1, 2, 3 ve 4 değerlerini alır. Bu alternatiflerin her ikisi de birer birer hatalara neden olabilir.
Böyle başka bir hata oluşabilir bir do-while yerine kullanılan bir süre döngüsü (veya tam tersine). Bir do-while kez en az çalışmasını garanti edilir.
Diziyle ilgili karışıklık, programlama dillerindeki farklılıklardan da kaynaklanabilir. 0'dan numaralandırma en yaygın olanıdır, ancak bazı diller dizi numaralandırmaya 1 ile başlar. Pascal'ın kullanıcı tanımlı dizinleri olan dizileri vardır. Bu, dizi indekslerini problem alanından sonra modellemeyi mümkün kılar.
çit direği hatası
Bir çit direği hatası (bazen telgraf direği, sokak lambası direği veya çit hatası olarak adlandırılır ), belirli bir tek tek hata türüdür. Bu hatanın erken bir açıklaması Vitruvius'un eserlerinde görülür . Aşağıdaki sorun hatayı göstermektedir:
3 fit aralıklı direklerle 30 fit uzunluğunda düz bir çit inşa ederseniz, kaç direk gerekir?
10 gönderinin ortak cevabı yanlış. Bu yanıt, çitin uzunluğunun, bölüm hatalı bir şekilde direk sayısı olarak sınıflandırılmasıyla, her bir direk arasındaki boşlukla bölünmesinden gelir. Gerçekte, çitin 10 bölümü ve 11 direği vardır.
Bu senaryoda, n bölümlü bir çitin n + 1 direği olacaktır . Tersine, çit n direk içeriyorsa , n - 1 bölüm içerecektir . Bu ilişki, ters hata ile uğraşırken dikkate alınması önemlidir. Mesaj sayısı bilindiğinde ve bölüm sayısının aynı olduğu varsayıldığında ters hata oluşur. Çitin tasarımına bağlı olarak bu varsayım doğru veya yanlış olabilir.
Aşağıdaki sorun, ters hatayı gösterir:
Eğer n mesajınız varsa , aralarında kaç bölüm var?
Çit tasarımının yorumu, bu sorunun cevabını değiştiriyor. Bir çit için doğru bölüm sayısı n - 1'dir, eğer çit, her bir ucunda bir direk ile sınırlandırılmış serbest duran bir hat parçası ise (örneğin, iki geçiş yolu boşluğu arasındaki bir çit), n çit bir tam oluşturuyorsa, serbest duran döngü (örneğin, bir boks ringi gibi üst üste binerek erişilebilen muhafaza) veya hat segmenti benzeri bir çitin (örneğin, arasında bir çit ve duvara sabitlenmiş bir çitin uçlarında direkler oluşmuyorsa) n + 1 iki bina). Kesin problem tanımı dikkatlice düşünülmelidir, çünkü bir durum için kurulum diğer durumlar için yanlış cevap verebilir. Fencepost hataları, aralarındaki boşluklardan ziyade şeyleri saymaktan veya bunun tersinden veya bir satırın bir veya iki ucunun sayılması gerektiğini düşünmeyi ihmal etmekten kaynaklanır.
Fencepost hataları uzunluk dışındaki birimlerde de meydana gelebilir. Örneğin, bloklar arasında 10 yıllık aralıklarla yerleştirilmiş 120 bloktan oluşan Zaman Piramidi'nin inşasının, ilk bloğun kurulumundan son bloğa kadar 1.190 yıl (1.200 değil) sürmesi planlanıyor. En erken fencepost hataları dahil sefer biri Jülyen takvimi başlangıçta yanlış sıçrama yılı hesaplanan nedeniyle her dörtten üç yılda yerine bir sıçrama yılı sayım inclusively ziyade münhasıran, verimli etmek.
"Fencepost hatası", nadiren, giriş değerlerindeki beklenmedik düzenliliklerin neden olduğu ve (örneğin) teorik olarak verimli bir ikili ağaç veya karma işlevi uygulamasını tamamen engelleyebilen bir hatayı ifade edebilir . Bu hata, bir algoritmanın beklenen ve en kötü durum davranışları arasındaki farkı içerir .
Daha büyük sayılarda, birer birer kapalı olmak çoğu zaman önemli bir sorun değildir. Bununla birlikte, daha küçük sayılarda ve doğruluğun çok önemli olduğu belirli durumlarda, tek tek bir hata yapmak felaket olabilir. Bazen bir sonraki kişi aynı hatayı tekrar yaparsa (elbette hata tersine çevrilebilir) birisi yanlış bir hesaplama yaparak böyle bir sorun tekrar eder ve bu nedenle daha da kötüleşir.
Bu hatanın bir örneği , parametreleri olan ve olmayan doğrusal enterpolasyon fonksiyonu ile MATLAB hesaplama dilinde ortaya çıkabilir . Üçüncü parametreyi artış sayısı olarak yanlış anlayan bir programcı, bunun bir dizi elde edeceğini umabilir, ancak bunun yerine .
linspace() (lower value, upper value, number of values)(lower value, upper value, number of increments)linspace(0,10,5)[0, 2, 4, 6, 8, 10][0, 2.5, 5, 7.5, 10]
Güvenlik etkileri
Güvenlikle ilgili bir hatayla sonuçlanan yaygın bir tek tek hata, C standart kitaplık strncat yordamının yanlış kullanılmasından kaynaklanır . İle ilgili yaygın bir yanlış anlama strncat, garantili boş sonlandırmanın maksimum uzunluğun ötesine yazmayacağıdır. Gerçekte, belirtilen maksimum uzunluğun bir bayt ötesinde bir sonlandırıcı boş karakter yazacaktır. Aşağıdaki kod böyle bir hata içeriyor:
void foo (char *s)
{
char buf[15];
memset(buf, 0, sizeof(buf));
strncat(buf, s, sizeof(buf)); // Final parameter should be: sizeof(buf)-1
}
Gibi işlevleri - 1 bayt çıkarmak için bir edip ihtiyaçlarına göre tutarlı olmadığı için hatalar C kütüphanesini kullanarak yaygındır Off-birer fgets()ve strncpyonları (verilen uzunluğu geçmiş yazma asla fgets()çıkarır 1 kendisi ve sadece verilerini geri çağırır (uzunluk − 1) bayt), diğerleri ise strncatkendilerine verilen uzunluğu aşacak şekilde yazacaktır. Bu yüzden programcının hangi fonksiyonlar için 1 çıkarmaları gerektiğini hatırlaması gerekir.
Bazı sistemlerde ( özellikle küçük endian mimarilerinde) bu, çerçeve işaretçisinin en az anlamlı baytının üzerine yazılmasına neden olabilir . Bu, bir saldırganın arama rutini için yerel değişkenleri ele geçirebileceği, kötüye kullanılabilir bir duruma neden olabilir.
Genellikle bu tür sorunlardan kaçınmaya yardımcı olan bir yaklaşım, yazılacak maksimum karakter sayısı yerine ara belleğin toplam uzunluğuna göre ne kadar yazılacağını hesaplayan bu işlevlerin türevlerini kullanmaktır. Bu tür işlevler strlcatve içerir ve strlcpygenellikle "daha güvenli" olarak kabul edilirler, çünkü bunlar yanlışlıkla bir arabelleğin sonundan sonra yazmaktan kaçınmayı kolaylaştırır. (Yukarıdaki kod örneğinde, strlcat(buf, s, sizeof(buf))bunun yerine çağırmak hatayı ortadan kaldırır.)
Ayrıca bakınız
daha fazla okuma
- Matt Parker (2021). Humble Pi: Gerçek Dünyada Matematik Yanlış Gittiğinde . nehirbaşı kitapları. ISBN'si 978-0593084694.
Notlar ve referanslar
Notlar
Referanslar
- Bu yazının önceki sürümü dayanıyordu fencepost hatası en FOLDOC ile kullanılabilir, izin .
- Dijkstra, Edsger Wybe (2 Mayıs 2008). "Numaralandırma neden sıfırdan başlamalıdır (EWD 831)" . EW Dijkstra Arşivi . Austin'deki Teksas Üniversitesi . 2011-03-16 alındı .
- Gelen Ortak Zayıflık Sayım sisteminin bu konu olarak listelenir Kapalı-by-tek Hata: CWE-193