C ++ 'da Segmentasyon hatalarını düzeltme


95

Windows ve Unix için çapraz platform C ++ programı yazıyorum. Pencere tarafında, kod derlenecek ve sorunsuz çalışacaktır. Unix tarafında, derlenecek ancak çalıştırmaya çalıştığımda bir segmentasyon hatası alıyorum. İlk önsezim, işaretçilerle ilgili bir sorun olduğudur.

Segmentasyon hatası hatalarını bulmak ve düzeltmek için iyi yöntemler nelerdir?

Yanıtlar:


135
  1. Uygulamanızı ile derleyin -g, ardından ikili dosyada hata ayıklama sembollerine sahip olacaksınız.

  2. gdbGdb konsolunu açmak için kullanın .

  3. fileKonsolda uygulamanızın ikili dosyasını kullanın ve iletin.

  4. runUygulamanızın başlaması gereken tüm bağımsız değişkenleri kullanın ve iletin.

  5. Segmentasyon Hatasına neden olacak bir şey yapın .

  6. Tür btiçinde gdbbir yığın izleme almak için konsola segmentasyon Fayı .


Onun gbağlamında derlenmesi ne anlama geliyor CMake?
Schütze

2
Hata ayıklama derleme türünü etkinleştirin. Tek yolu cmake -DCMAKE_BUILD_TYPE=Debug.
Antonin Décimo

36

Bazen sorunun asıl nedeni kazanın kendisi değildir - belki de bellek daha erken bir noktada parçalandı, ancak bozulmanın kendini göstermesi biraz zaman aldı. İşaretçi sorunları için çok sayıda denetim içeren valgrind'e göz atın (dizi sınırları denetimi dahil). Size sadece kazanın meydana geldiği satırı değil , sorunun nerede başladığını söyleyecektir .


19

Sorun ortaya çıkmadan önce, mümkün olduğunca kaçınmaya çalışın:

  • Kodunuzu olabildiğince sık derleyin ve çalıştırın. Hatalı parçayı bulmak daha kolay olacaktır.
  • Düşük seviyeli / hataya açık rutinleri özetlemeye çalışın, böylece nadiren doğrudan bellekle çalışmanız gerekecek (programınızın modellenmesine dikkat edin)
  • Bir test süiti oluşturun. Şu anda neyin çalıştığına, neyin artık çalışmadığına vb. Genel bir bakışa sahip olmak, sorunun nerede olduğunu anlamanıza yardımcı olacaktır ( Boost testi olası bir çözümdür, ben bunu kendim kullanmıyorum, ancak belgeler ne tür olduğunu anlamanıza yardımcı olabilir. bilgi görüntülenmelidir).

Hata ayıklama için uygun araçları kullanın. Unix'te:

  • GDB size nerede çökmeyi programladığınızı söyleyebilir ve hangi bağlamda görmenize izin verir.
  • Valgrind , bellekle ilgili birçok hatayı tespit etmenize yardımcı olacaktır.
  • GCC ile mudflap'ı GCC, Clang ve Ekim ayından itibaren deneysel olarak MSVC ile de kullanabilirsiniz Address / Memory Sanitizer . Valgrind'in yapmadığı bazı hataları algılayabilir ve performans kaybı daha hafiftir. Flag ile derlenerek kullanılır -fsanitize=address.

Son olarak her zamanki şeyleri tavsiye ederim. Programınız ne kadar okunabilir, bakımı yapılabilir, anlaşılır ve derli toplu olursa, hata ayıklama o kadar kolay olacaktır.


5

Unix'te valgrindsorunları bulmak için kullanabilirsiniz . Ücretsiz ve güçlüdür. Kendiniz yapmayı tercih ederseniz, her yeni nesneden önce ve sonra 1 bayta sahip olduğunuz bir yapılandırma ayarlamak için newve deleteoperatörlerini aşırı yükleyebilirsiniz 0xDEADBEEF. Ardından her yinelemede ne olduğunu izleyin. Bu, her şeyi yakalayamayabilir (bu baytlara dokunmanız bile garanti edilmez) ancak geçmişte bir Windows platformunda benim için çalıştı.


1
bu 1 bayt yerine 4 bayt olur ... ama prensip iyi.
Jonas Wagner


Göreyim seni. Hepimiz burada başkalarına yardım etmek üzereyiz, böylece yardımcı olabilecek her şey eklenmelidir.
buğdaylar

Aşırı yükleme newve deletesüper yararlı olsa -fsanitize=addressda, derleyici sorunlar için çalışma zamanı algılamasında derleyeceği ve belleği otomatik olarak ekrana dökerek hata ayıklamayı kolaylaştıracağı için kullanmak daha iyi bir seçenektir.
Tarick Welling

3

Evet, işaretçilerle ilgili bir sorun var. Büyük olasılıkla doğru şekilde başlatılmamış bir tane kullanıyorsunuz, ancak aynı zamanda bellek yönetiminizi çift serbest bırakma veya benzeri bir şeyle karıştırmanız da mümkündür.

Yerel değişkenler olarak başlatılmamış işaretçilerden kaçınmak için, onları olabildiğince geç, tercihen anlamlı bir değerle başlatılabilecekleri zaman (ve bu her zaman mümkün değildir) bildirmeyi deneyin. Kodu inceleyerek, kullanılmadan önce bir değeri olacağına kendinizi ikna edin. Bununla ilgili zorluk yaşıyorsanız, onları boş gösterici sabitine (genellikle NULLveya olarak yazılır 0) başlatın ve kontrol edin.

Üye değerler olarak başlatılmamış işaretçilerden kaçınmak için, yapıcıda doğru şekilde başlatıldıklarından ve kopya oluşturucularda ve atama işleçlerinde düzgün şekilde işlendiğinden emin olun. GüvenmeinitDiğer başlatma işlemleri için yapabilseniz de, bellek yönetimi için işleve .

Sınıfınızın kopya oluşturuculara veya atama işleçlerine ihtiyaç duymuyorsa, bunları özel üye işlevleri olarak ilan edebilir ve asla tanımlayabilirsiniz. Açıkça veya örtük olarak kullanılırsa bu bir derleyici hatasına neden olur.

Mümkün olduğunda akıllı işaretçiler kullanın. Buradaki en büyük avantaj, onlara bağlı kalırsanız ve onları tutarlı bir şekilde kullanırsanız, yazmaktan tamamen kurtulabilirsiniz deleteve hiçbir şey iki kez silinmez.

Mümkün olduğunda, C tarzı dizeler ve diziler yerine C ++ dizelerini ve kapsayıcı sınıflarını kullanın. Sınır kontrolünü zorlayacağından .at(i)yerine kullanmayı düşünün [i]. Derleyicinizin veya kitaplığınızın [i], en azından hata ayıklama modunda sınırları denetleyecek şekilde ayarlanıp ayarlanamayacağını görün . Segmentasyon hataları, mükemmel şekilde iyi işaretçilerin üzerine gereksiz yazan arabellek taşmalarından kaynaklanabilir.

Bunları yapmak, bölümleme hataları ve diğer bellek problemleri olasılığını önemli ölçüde azaltacaktır. Şüphesiz her şeyi düzeltmekte başarısız olacaklar ve bu yüzden sorun yaşamadığınızda ara sıra valgrind, yaptığınız zaman da valgrind ve gdb kullanmalısınız.


1

Böyle şeyleri düzeltmek için kullanabileceğim herhangi bir metodoloji bilmiyorum. Elimizdeki sorun, programınızın davranışının tanımlanmamış olmasıdır (SEGFAULT'un bir tür UB'den kaynaklanmadığı hiçbir durum bilmiyorum) .

Ortaya çıkmadan sorunu önlemek için her türlü "metodoloji" vardır. Önemli olanlardan biri RAII'dir.

Bunun yanı sıra, en iyi psişik enerjinizi ona vermelisiniz.

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.