<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <!-- this stylesheet will later on be added by lfparser automatically: --> <style type="text/css"> <!-- pre { font-family:monospace,Courier } pre.code { font-family:monospace,Courier;background-color:#aedbe8; } p.code { width:80%; alignment:center; background-color:#aedbe8; border-style:none; border-width:medium; border-color:#aedbe8; padding:0.1cm ; text-align:left } --> </style> <title></title> </head> <body> <h1>Bu neden çalışmıyor? Linux uygulamalarındaki hatalar nasıl belirlenebilir ve düzeltilebilir?</h1> <h4>ArticleCategory:</h4> UNIXBasics <h4>AuthorImage:[Here we need a little image from you]</h4> <img src="../../common/images/Guido-S.gif" alt= "[Photo of the Author]" height="164" width="173"> <h4>TranslationInfo:[Author + translation history. mailto: or http://homepage]</h4> <p>original in en <a href="http://main.linuxfocus.org/%7Eguido/">Guido Socher</a></p> <p>en to tr:<A href="mailto:erdal(at)linuxfocus.org">Erdal Mutlu</A> </p> <h4>AboutTheAuthor:[A small biography about the author]</h4> <p>Guido, sorunları araştırma fırsatı tanıdıkları için Linux gibi açık kaynak kodlu sistemlerden hoşlanmaktadır. Eğer, zaman ayırabilirseniz, sorunların ana kaynağını bulmanız olasıdır. </p> <h4>Abstract:</h4> Herkes Linux altında çalışan uygulamaların hatalarını kolayca belirlenebileceğinden ve düzeltilebileceğinden söz ediyor. Ne yazık ki, bunun nasıl yapıldığını anlatan belgeler bulmak çok zor. Bu yazıda, bir uygulamanın aslında nasıl çalıştığını öğrenmeden, uygulamada oluşan hataları bulmayı öğreneceksiniz. <h4>ArticleIllustration:</h4> <img src="../../common/images2/illustration343.png" alt="bug" hspace="10"> <h4>ArticleBody:</h4> <h2>Giriş</h2> Herşey düzgün ve uygulamadan beklendiği gibi çalıştığı sürece, bir uygulamanın açık mı yoksa kapalı kaynak koda sahip mi olduğu kullanıcı açısında hiç önemli değildir. Ancak, birşeyler artık çalışmamaya başladığında durum değişmektedir ve herkes er veya geç böyle bir durumla karşı karşıya kalamaktadır. <p> Kaynak kodu kapalı olan sistemlerde bir sorun ortaya çıktığında, yapabilecekleriniz genelde aşağıdaki iki seçenekle sınırlıdır: <ul> <li>Sorunu bildirmek ve giderilmesi için ödemede bulunmak. <li>Uygulamayı yeniden yüklemek ve çalışması için dua etmek. </ul> Linux altında bu seçeneklere sahipsiniz tabii, ama bunların yanısıra sorunun nedenini araştırmaya da başlayabilirsiniz. Burada, uygulamayı yazanın bir başkası olması ve uygulamanın nasıl çalıştığı hakkında bir fikrinizin olmayışı gibi, bazı engeller vardır. <p> Bu engellere karşın, programın tüm kaynak kodunu okumadan ve hasıl çalıştığını öğrenmeden önce, yapabileceğiniz şeyler vardır. <h2>Çetele dosyaları</h2> Herkesçe bilinen ve yapabileceğiniz şey, /var/log/ dizinindeki çetele dosyalarına bakmaktır. Oradaki dosyalarda, dosya isimleriyle içerikleri yapılandırılabilir. Genelde bakmanız gerekn dosya /var/log/messages dir. Çok fazla çetele bilgisi oluşturan uygulamaların kendi çetele dosyaları olabilir (/var/log/httpd/ /var/log/exim vs.).<br> Çoğu Linux dağıtımında sistem çetele verilerinin saklanmasından syslog servisi sorumludur ve bu /etc/syslog.conf yapılandırma dosyası tarafından denetlenebilir. Yapılandırma dosyasının yapısı "man syslog.conf"'da belgelendirilmiştir. <br><br> Uygulamasında çetele verileri yaratmak isteyen bir yazılımcı varsa, programına syslog satırları eklemesi yeterlidir. syslog, printf gibi çalışmaktadır, farkı sistem çetele dosyasına yazmasıdır. Çetelesi tutulacak iletinin yanı sıra fonksiyona, önceliği(priority) ve olanağı(facility) belirtmek gerekiyor: <pre class="code"> #include <syslog.h> void openlog(const char *ident, int option, int facility); void syslog(int priority, const char *format, ...); void closelog(void); facility (olanak) iletiyi gönderenin hangi türden bir uygulama olduğunu belirler. priority (öncelik) iletinin önemini belirtmektedir. priority (öncelik) için olası değerler şunlardır: LOG_EMERG LOG_ALERT LOG_CRIT LOG_ERR LOG_WARNING LOG_NOTICE LOG_INFO LOG_DEBUG </pre> C programlama dilinde yazılan her program sistem çetele dosyasına yazabilir. Diğer programlama dillerin de kendi olanakları vardır. Kabuk betikleri bile çetele tutabilir: <pre class="code"> logger -p err "Bu yazı /var/log/messages dosyasına yazılacaktır." </pre> syslog'un standart yapılandırma dosyasında (/etc/syslog.conf) başka yapılandırmaların yanısıra, aşağıdakine benzer bir satır olması gerekir: <pre class="code"> # Log anything (except mail) of level info or higher. # Don't log private authentication messages. *.info;mail.none;authpriv.none /var/log/messages </pre> "*.info" öncelik seviyesi LOG_INFO veya daha yüksek olan herşeyi çetele dosyasına yazacaktır. Daha fazla bilgi görmek isterseniz, bunu "*.debug" yapıp syslog'u yeniden başlatabilirsiniz (/etc/init.d/syslog restart). <br><br> Bir uygulamada hata aramanın adımları aşağıdaki gibi olmalıdır: <pre class="code"> 1) tail -f /var/log/messages komutunu çalıştırın ve başka bir kabuktan hatalı uygulamayı başlatın. Belkide daha şimdiden yanlış giden şeyler hakkında bilgi elde edebilrsiniz. 2) Eğer, 1. adım yeterli olmazsa, /etc/syslog.conf'daki *.info yu *.debug olarak değiştirin ve "/etc/init.d/syslog restart" komutuyla syslog servisini yeniden başlatıp ve 1. adıma dönün. </pre> Bu yöntemin eksiği, yazılımcının kaynak kodunda ne kadar denetim yaptığına ve bunları çetele dosyasına gönderip göndermemesine olmasıdır. Eğer, önemli yerlere syslog fonksiyonunu yereştirmemişse, hiçbir şey göremeyebilirsiniz. Başka bir deyişle, sorunları belirleyebilmenin şartı, yazılımcının bazı yerlerde sorunların çıkabileceğini öngörmüş olmasıdır. <h2>strace</h2> Linux altında çalışan bir uygulama 3 tür fonksiyon çağırabilir: <ol> <li>Kendi kodu içerisindeki bir fonksiyonu. <li>Kütüphane fonksiyonlarını. <li>Sistem çağrılarını. </ol> Kütüphane fonksiyonları, uygulamanın kendi fonksiyonlarına benzemektedir, tek farkları başka bir paket içerisinde bulunmalarıdır. Sistem çağrıları ise, her ne kadar fonksiyonlar gibi gözükseler de, çekirdekle haberleşen bir yapıları vardır. Ekrana yazmak, dosyadan okumak veya dosyaya yazmak, klavyeden gelen girişleri okumak, ağ üzerinden ileti göndermek gibi, bilgisayarınızın donanımlarıyla etkileşimde bulunma sırasında uygulamalar çekirdekle konuşmaktadır. <br><br> Bu sistem çağrıların arasına girilebilir, böylece uygulama ile çekirdek arasındaki haberleşme takip edilebilir.<br><br> Yapılandırma dosyasını bulamamak veya bir dizine yazı yazmak için yeterli erişim haklarına sahip olmamak, bir uygulamanın düzgün çalışmamasının sıkça rastlanan nedenlerdir. Bu sorunlar strace ile kolayca belirlenebilir. Bu durumda ilgili sistem çağrısının adı 'open' olacaktır. <br><br> strace'i aşağıdaki gibi kullanabilirsiniz:: <pre class="code"> strace your_application </pre> İşte bir örnek: <pre class="code"> # strace /usr/sbin/uucico execve("/usr/sbin/uucico", ["/usr/sbin/uucico", "-S", "uucpssh", "-X", "11"], [/* 36 vars */]) = 0 uname({sys="Linux", node="brain", ...}) = 0 brk(0) = 0x8085e34 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40014000 open("/etc/ld.so.preload", O_RDONLY) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=70865, ...}) = 0 mmap2(NULL, 70865, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40015000 close(3) = 0 open("/lib/libnsl.so.1", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\300;\0"..., 1024) = 1024 fstat64(3, {st_mode=S_IFREG|0755, st_size=89509, ...}) = 0 mmap2(NULL, 84768, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x40027000 mprotect(0x40039000, 11040, PROT_NONE) = 0 mmap2(0x40039000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x11) = 0x40039000 mmap2(0x4003a000, 6944, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x4003a000 close(3) = 0 open("/lib/libc.so.6", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0`X\1\000"..., 1024) = 1024 fstat64(3, {st_mode=S_IFREG|0755, st_size=1465426, ...}) = 0 mmap2(NULL, 1230884, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x4003c000 mprotect(0x40163000, 22564, PROT_NONE) = 0 mmap2(0x40163000, 12288, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0x126) = 0x40163000 mmap2(0x40166000, 10276, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED|MAP_ANONYMOUS, -1, 0) = 0x40166000 close(3) = 0 munmap(0x40015000, 70865) = 0 brk(0) = 0x8085e34 brk(0x8086e34) = 0x8086e34 brk(0) = 0x8086e34 brk(0x8087000) = 0x8087000 open("/usr/conf/uucp/config", O_RDONLY) = -1 ENOENT (No such file or directory) rt_sigaction(SIGINT, NULL, {SIG_DFL}, 8) = 0 rt_sigaction(SIGINT, {0x806a700, [], SA_RESTORER|SA_INTERRUPT, 0x40064d58}, NULL, 8) = 0 rt_sigaction(SIGHUP, NULL, {SIG_DFL}, 8) = 0 rt_sigaction(SIGHUP, {0x806a700, [], SA_RESTORER|SA_INTERRUPT, 0x40064d58}, NULL, 8) = 0 rt_sigaction(SIGQUIT, NULL, {SIG_DFL}, 8) = 0 rt_sigaction(SIGQUIT, {0x806a700, [], SA_RESTORER|SA_INTERRUPT, 0x40064d58}, NULL, 8) = 0 rt_sigaction(SIGTERM, NULL, {SIG_DFL}, 8) = 0 rt_sigaction(SIGTERM, {0x806a700, [], SA_RESTORER|SA_INTERRUPT, 0x40064d58}, NULL, 8) = 0 rt_sigaction(SIGPIPE, NULL, {SIG_DFL}, 8) = 0 rt_sigaction(SIGPIPE, {0x806a700, [], SA_RESTORER|SA_INTERRUPT, 0x40064d58}, NULL, 8) = 0 getpid() = 1605 getrlimit(RLIMIT_NOFILE, {rlim_cur=1024, rlim_max=1024}) = 0 close(3) = -1 EBADF (Bad file descriptor) close(4) = -1 EBADF (Bad file descriptor) close(5) = -1 EBADF (Bad file descriptor) close(6) = -1 EBADF (Bad file descriptor) close(7) = -1 EBADF (Bad file descriptor) close(8) = -1 EBADF (Bad file descriptor) close(9) = -1 EBADF (Bad file descriptor) fcntl64(0, F_GETFD) = 0 fcntl64(1, F_GETFD) = 0 fcntl64(2, F_GETFD) = 0 uname({sys="Linux", node="brain", ...}) = 0 umask(0) = 022 socket(PF_UNIX, SOCK_STREAM, 0) = 3 connect(3, {sa_family=AF_UNIX, path="/var/run/.nscd_socket"}, 110) = -1 ENOENT (No such file or directory) close(3) = 0 open("/etc/nsswitch.conf", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=499, ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40015000 read(3, "# /etc/nsswitch.conf:\n# $Header:"..., 4096) = 499 read(3, "", 4096) = 0 close(3) = 0 munmap(0x40015000, 4096) = 0 open("/etc/ld.so.cache", O_RDONLY) = 3 fstat64(3, {st_mode=S_IFREG|0644, st_size=70865, ...}) = 0 mmap2(NULL, 70865, PROT_READ, MAP_PRIVATE, 3, 0) = 0x40015000 close(3) = 0 open("/lib/libnss_compat.so.2", O_RDONLY) = 3 read(3, "\177ELF\1\1\1\0\0\0\0\0\0\0\0\0\3\0\3\0\1\0\0\0\300\25"..., 1024) = 1024 fstat64(3, {st_mode=S_IFREG|0755, st_size=50250, ...}) = 0 mmap2(NULL, 46120, PROT_READ|PROT_EXEC, MAP_PRIVATE, 3, 0) = 0x40169000 mprotect(0x40174000, 1064, PROT_NONE) = 0 mmap2(0x40174000, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_FIXED, 3, 0xa) = 0x40174000 close(3) = 0 munmap(0x40015000, 70865) = 0 uname({sys="Linux", node="brain", ...}) = 0 brk(0) = 0x8087000 brk(0x8088000) = 0x8088000 open("/etc/passwd", O_RDONLY) = 3 fcntl64(3, F_GETFD) = 0 fcntl64(3, F_SETFD, FD_CLOEXEC) = 0 fstat64(3, {st_mode=S_IFREG|0644, st_size=1864, ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40015000 _llseek(3, 0, [0], SEEK_CUR) = 0 read(3, "root:x:0:0:root:/root:/bin/bash\n"..., 4096) = 1864 close(3) = 0 munmap(0x40015000, 4096) = 0 getuid32() = 10 geteuid32() = 10 chdir("/var/spool/uucp") = 0 open("/usr/conf/uucp/sys", O_RDONLY) = -1 ENOENT (No such file or directory) open("/var/log/uucp/Debug", O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY, 0600) = 3 fcntl64(3, F_GETFD) = 0 fcntl64(3, F_SETFD, FD_CLOEXEC) = 0 fcntl64(3, F_GETFL) = 0x401 (flags O_WRONLY|O_APPEND) fstat64(3, {st_mode=S_IFREG|0600, st_size=296, ...}) = 0 mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = 0x40015000 _llseek(3, 0, [0], SEEK_CUR) = 0 open("/var/log/uucp/Log", O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY, 0644) = 4 fcntl64(4, F_GETFD) = 0 fcntl64(4, F_SETFD, FD_CLOEXEC) = 0 fcntl64(4, F_GETFL) = 0x401 (flags O_WRONLY|O_APPEND) </pre> Burada ne görüyoruz? İsterseniz aşağıdaki satırlara bir göz atalım: <pre class="code"> open("/etc/ld.so.preload", O_RDONLY) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY) = 3 </pre> Elde edilen çıktıya bir bakalım. Program ilk önce /etc/ld.so.preload dosyasını okumaya çalışıyor ve başarısız oluyor, daha sonra /etc/ld.so.cache dosyasını okumaktadır. Burada başarılı olmakta ve 3 nolu dosya tanımlayıcısını elde etmektedir. /etc/ld.so.preload dosyasını okuyamaması tam olarak bir hata anlamına gelmeyebilir, çünkü belkide program varsa ilk önce bu dosyayı okumak istemiştir. Başka bir deyişle, bir dosyayı okuyamamak, mutlaka hata anlamına gelmeyebilir. Herşey programın tasarlanma şekline bağlıdır. strace çıktısındaki tüm open sistem çağrılarına bir göz atalım: <pre class="code"> open("/usr/conf/uucp/config", O_RDONLY)= -1 ENOENT (No such file or directory) open("/etc/nsswitch.conf", O_RDONLY) = 3 open("/etc/ld.so.cache", O_RDONLY) = 3 open("/lib/libnss_compat.so.2", O_RDONLY) = 3 open("/etc/passwd", O_RDONLY) = 3 open("/usr/conf/uucp/sys", O_RDONLY) = -1 ENOENT (No such file or directory) open("/var/log/uucp/Debug", O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY, 0600) = 3 open("/var/log/uucp/Log", O_WRONLY|O_APPEND|O_CREAT|O_NOCTTY, 0644) = 4 open("/etc/ld.so.preload", O_RDONLY) = -1 ENOENT (No such file or directory) open("/etc/ld.so.cache", O_RDONLY) = 3 </pre> Şimdi program /usr/conf/uucp/config dosyasını okumaya çalışıyor. Ooo! Ama bu çok garip benim dosyam /etc/uucp/config dir! Ve /etc/uucp/config dosyasını açmak isteyen hiçbir satır çıktıda görünmüyor. Hata bu olmalı işte. Herhalde yapılandırma dosyasının yeri, programın derlenmesi sırasında yanlış belirtildi. <br><br> Gördüğünüz gibi strace programı çok faydalı olabiliyor. Tek sorun, strace'in çıktısını tam olarak anlayabilmek için C programlama bilgisi gerektirmesidir, ama genelde sizin bu kadar derine inmeniz gerekmeyecektir. <h2>gdb ve core dosyaları</h2> Bazen öyle oluyor ki, program 'Segmentation fault (core dumped)' iletisini görüntüleyerek aniden çöküyor. Bunun anlamı, bir programlama hatasından dolayı program, ayırttığının ötesinde bir bellek alanına yazmaya çalışmasıdır. Bu özellikle, program birkaç byte fazla yazmaya kalkıştığında ve sadece arasıra ortaya çıkan bir olay olabilir. Bunun nedeni, bellek ayırtma işleminin parça parça olması ve bazen rastlantı eseri fazladan gelen birkaç byte için yer kalıyor olmasıdır, yoksa böyle bir durum önceden kestirilmesi güç olaylara yol açabilir. <br><br> 'Segmentation fault' hatası alındığında bulunulan dizinde (Genelde bu sizin ev dizininiz oluyor.), bir core (Programın bellek kullanım durumunu içeren ve bir hata ayıklayıcısının (debugger) anlayacağı biçimdeki bir dosya.) dosyası oluşmaktadır. core dosyası, hatanın oluştuğu andaki programın bellek kullanımının bir çıktısıdır. Bazı kabuk ortamları core dosyaların oluşturulup oluşturulmayacağını denetleyen olanaklar içermektedir. bash kabuğu kullanıldığında sözgelimi, benimsenmiş değer olarak core dosyaları oluşturulması iptal edilmiştir. Bu dosyaların oluşturulmasını istiyorsanız, aşağıdaki komutu çalıştırmanız gerekir: <pre class="code"> # ulimit -c unlimited # ./lshref -i index.html,index.htm test.html Segmentation fault (core dumped) Exit 139 </pre> Oluşan core dosyası, gdb hata ayıklayıcısı kullanılarak sorunun neden kaynaklandığı araştırması yapılabilir. gdb'yi çalıştırmadan önce, doğru core dosyasına baktığınızı denetlemede yarar vardır: <pre class="code"> # file core.16897 core.16897: ELF 32-bit LSB core file Intel 80386, version 1 (SYSV), SVR4-style, <b>from 'lshref'</b> </pre> Tamam, bozuk olan program lshref dir ve onu şimdi gdb'ye yükleyebiliriz. gdb'yi bir core dosyasını incelemek için çalıştırmak istediğinizde, core dosyasının adıyla birlikte, bu dosyanın oluşmasına neden olan programı da belirtmeniz gerekmektedir. <pre class="code"> # <b>gdb ./lshref core.23061 </b> GNU gdb Linux (5.2.1-4) Copyright 2002 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. Core was generated by `./lshref -i index.html,index.htm test.html'. <b>Program terminated with signal 11, Segmentation fault.</b> Reading symbols from /lib/libc.so.6...done. Loaded symbols for /lib/libc.so.6 Reading symbols from /lib/ld-linux.so.2...done. Loaded symbols for /lib/ld-linux.so.2 <b>#0 0x40095e9d in strcpy () from /lib/libc.so.6</b> (gdb) </pre> Şimdi artık programın strcpy fonksiyonunu kullanırken çöktüğünü biliyoruz. Ancak, program içerisinde strcpy birden fazla yerde kullanılıyor olabilir. <br><br> Genel olarak bu durumda, programın hangi yerinde hata oluştuğunu belirlemek için iki olasılık vardır: <ol> <li>Programı hata ayıklama seçeneği ile (gcc için -g) yeniden derlemek. <li>gdb'de yığıt izlemesi yapmak. </ol> Bizim durumuzdaki sorun, strcpy'nin bir kütüphane fonksiyonu olması ve libc kütüphanesi dahil tüm kodu yeniden derlesek bile, en fazla C kütüphanesinin belli bir satırında başarısız olunduğunu elde edebileceğiz.<br><br> Bize gerekli olan ise, yığıtı inceleyip, sorun oluşmadan hemen önce hangi fonksiyonun strcpy'yi çağırdığını belirlemektir. gdb'de böyle bir şeyin yapılmasına olanak veren komutun adı 'backtrace' dir. Ancak bu, core dosyası kullanmamaktadır. Dolayısıyla, hatayı programı gdb içerisinde oluşturacak şekilde yeniden oluşturmanız gerekir: <pre class="code"> gdb ./lshref core.23061 GNU gdb Linux (5.2.1-4) Copyright 2002 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. Core was generated by `./lshref -i index.html,index.htm test.html'. Program terminated with signal 11, Segmentation fault. Reading symbols from /lib/libc.so.6...done. Loaded symbols for /lib/libc.so.6 Reading symbols from /lib/ld-linux.so.2...done. Loaded symbols for /lib/ld-linux.so.2 #0 0x40095e9d in strcpy () from /lib/libc.so.6 (gdb) backtrace #0 0x40095e9d in strcpy () from /lib/libc.so.6 Cannot access memory at address 0xbfffeb38 <b>(gdb) run ./lshref -i index.html,index.htm test.html Starting program: /home/guido/lshref ./lshref -i index.html,index.htm test.html Program received signal SIGSEGV, Segmentation fault. 0x40095e9d in strcpy () from /lib/libc.so.6 (gdb) backtrace #0 0x40095e9d in strcpy () from /lib/libc.so.6 #1 0x08048d09 in string_to_list () #2 0x080494c8 in main () #3 0x400374ed in __libc_start_main () from /lib/libc.so.6 </b>(gdb) </pre> Şimdi görüyoruz ki, sorun yarat strcpy fonksiyonunu string_to_list() fonksiyonu, onu da main() çağırmıştır. string_to_list() fonksiyonuna bir bakalım: <pre class="code"> char **string_to_list(char *string){ char *dat; char *chptr; char **array; int i=0; <b>dat=(char *)malloc(strlen(string))+5000;</b> array=(char **)malloc(sizeof(char *)*51); strcpy(dat,string); </pre> malloc satırında bir yazım hatası var gibi gözüküyor. Aslında şöyle olmalıydı: <pre class="code"> dat=(char *)malloc(strlen(string)+5000); </pre> <br> Gerekli değişikliği yapıyor, programı yeniden derliyor ve ... yaşasın programımız çalışıyor. <br><br> İsterseniz, hatanın kütüphane dosyasında değil de uygulamanın bir yerinde olduğu durumu ele alan bir örnek üzerinde duralım. <br><br>İşte örneğimiz: <pre class="code"> #include <stdio.h> #include <stdlib.h> int add(int *p,int a,int b) { *p=a+b; return(*p); } int main(void) { int i; int *p = 0; /* a null pointer */ printf("result is %d\n", add(p,2,3)); return(0); } </pre> Programı derliyor: <pre class="code"> gcc -Wall -g -o exmp exmp.c </pre> ve çalıştırıyoruz ... <pre class="code"> # ./exmp Segmentation fault (core dumped) Exit 139 </pre> <pre class="code"> gdb exmp core.5302 GNU gdb Linux (5.2.1-4) Copyright 2002 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. Core was generated by `./exmp'. Program terminated with signal 11, Segmentation fault. Reading symbols from /lib/libc.so.6...done. Loaded symbols for /lib/libc.so.6 Reading symbols from /lib/ld-linux.so.2...done. Loaded symbols for /lib/ld-linux.so.2 <b> #0 0x08048334 in add (p=Cannot access memory at address 0xbfffe020 ) at exmp.c:6 6 *p=a+b; </b> </pre> gdb, hatanın 6. satırda ve 'p' işaretçisinin, erişim hakkı olmadığı bir bellek alanına erişmek isterken oluştuğunu söylemektedir. <br><br> Yükarıdaki programın ilgili yerine bakarark, sorunun p null işaretçisi (yani hiçbiryeri göstermeyen) olduğu ve ona veri yüklemek istenildiği hemen görülmektedir. Bu, kasıtlı hazırlanan bir örnek olduğundan, sorunu bulmak ve gidermek kolay oldu. <h2>Sonuç</h2> Programın asıl çalışması hakkında pek fazla bilgi sahibi olmadan bile, programda oluşan hataları bulabileceğimizi gördük. <br><br> Ben sözgelimi, bir grafik programındaki bir tuşun yanlış yerde görüntülenmesi gibi işlevsel hataları kasıtlı olarak burada ele almadım. Bu gibi durumlarda, programın işleyişinin bilinmesi gerekmektedir. Doğal olarak, bunun için daha fazla zaman harcamak gerekir ve nasıl yapılacağına ilişkin kesin bir tarif de yoktur. <br><br> Ancak, burada gösterilen basit hata bulma yöntemleri birçok durumda kullanılabilir. <br><br> Mutlu sorun gidermeler! </body> </html>