genau 8kb im std::string -> SIGSEGV, Segmentation fault
-
Hallo alle,
ich bin auch mal wider da! Nach längerer Pause bin ich jetzt mal wider am Programmieren und habe gleich ein Problem! Folgendes Testprogramm:#include <sys/mman.h> #include <sys/types.h> #include <fcntl.h> #include <sys/stat.h> #include <iostream> #include <string> int main ( void ) { struct stat st; int f; std::string filename="./8192byte.file"; std::string fileContent; char* rawContent; f = open(filename.c_str(), O_RDONLY); if(f == -1) { throw (std::string)"Cannot open "+ filename + " Reason: " + strerror(errno); return 1; } if(fstat(f, &st) == -1) { throw (std::string)"Cannot stat " + filename + " Reason: " + strerror(errno); return 1; } int tmpl_size = st.st_size; rawContent = (char *)mmap(0, tmpl_size , PROT_READ, MAP_SHARED, f, 0); fileContent = rawContent; if(munmap(rawContent, tmpl_size) == -1) { throw (std::string)"Failed to munmap reason:" + std::string( strerror(errno) ); } std::cout << fileContent << std::endl; return 0; }
Was die Datei 8192byte.file enthält ist egal! Z.B.
echo -n > 8192byte.file;i=0; while ( [ $i -lt 8192 ]);do echo -n "a">>8192byte.file;i=$[ i + 1 ];done
( dd geht auch aber dann ist mit Anzeigen schlecht! )
Wichtig ist, dass sie genau 8KB ( 8*1024) hat, eins mehr oder weniger und der Fehler tritt nicht auf!# wc -c 8192byte.file 8192 8192byte.file
Also los:
# g++ test.cpp -o test # ./test Segmentation fault # gdb ./test 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. This GDB was configured as "i386-linux"... (gdb) run Starting program: ./test Program received signal SIGSEGV, Segmentation fault. 0x4003b11f in string_char_traits<char>::length () from /usr/lib/libstdc++-libc6.2-2.so.3 (gdb) backtrace #0 0x4003b11f in string_char_traits<char>::length () from /usr/lib/libstdc++-libc6.2-2.so.3 #1 0x0804be12 in basic_string<char, string_char_traits<char>, __default_alloc_template<true, 0> >::assign () #2 0x0804bdc4 in basic_string<char, string_char_traits<char>, __default_alloc_template<true, 0> >::operator= () #3 0x0804a914 in main () #4 0x400a0da6 in __libc_start_main () from /lib/libc.so.6
Sch...., oder
Die Gegenprobe:# echo -n "n" >> 8192byte.file # ./test aaaaaaaaaaa( Ausgabe gekürzt ;-) aaaaaaaaaaab
Jemand eine Idee???
PS: Umgebung:
# uname -a Linux krutschel-kiste 2.4.18-bf2.4 #1 Son Apr 14 09:53:28 CEST 2002 i586 unknown # g++ --version 2.95.4 # g++-3.2 --version # auch getestet! g++-3.2 (GCC) 3.2.3 (Debian) # g++-3.3 --version # auch getestet! g++-3.3 (GCC) 3.3.2 (Debian) # /lib/libc.so.6 GNU C Library stable release version 2.3.2, by Roland McGrath et al. Copyright (C) 2003 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Compiled by GNU CC version 3.3.2 (Debian). Compiled on a Linux 2.6.0-test7 system on 2003-11-05. Available extensions: GNU libio by Per Bothner crypt add-on version 2.1 by Michael Glad and others linuxthreads-0.10 by Xavier Leroy BIND-8.2.3-T5B libthread_db work sponsored by Alpha Processor Inc NIS(YP)/NIS+ NSS modules 0.19 by Thorsten Kukuk Thread-local storage support included. Report bugs using the `glibcbug' script to <bugs@gnu.org>.
PPS: Das neue Forum macht mächtig was her!!!
-
Aus Deinem Quelltext werde ich nicht schlau.
Reduziere es mal auf ein Minimalbeispiel das sich Compilieren lässt.
-
Hallo,
if(fstat(f, &st) == -1) { throw (std::string)"Cannot stat " + filename + " Reason: " + strerror(errno); return 1; } int tmpl_size = st.st_size; rawContent = (char *)mmap(0, tmpl_size , PROT_READ, MAP_SHARED, f, 0);
tmpl_size sollte hier jetzt 8192 sein. Dann machst du folgendes:
fileContent = rawContent;
[nachtrag]
hier stand mist!
[/nachtrag]So nochma:
bei der o. Zeile, willst du den Inhalt von rawContent fileContent zuweisen.
Aber ist denn die Zeichenkette in rawContent Nullterminiert?mfg
v R
-
Knuddlbaer schrieb:
Aus Deinem Quelltext werde ich nicht schlau.
Reduziere es mal auf ein Minimalbeispiel das sich Compilieren lässt.
Bei mir läst sich das Beispiel Compilieren!
Das ist schon das (fast) minimalste was den Fehler zeigt und sich kompilieren läst!Wo gibt es den Verständnissprobleme?
-
virtuell Realisticer schrieb:
tmpl_size sollte hier jetzt 8192 sein. Dann machst du folgendes:
debuger bestätigt diese Annahme!
virtuell Realisticer schrieb:
fileContent = rawContent;
So nochma:
bei der o. Zeile, willst du den Inhalt von rawContent fileContent zuweisen.
Aber ist denn die Zeichenkette in rawContent Nullterminiert?Äh, ... keine Ahnung! Werde ich mir mal angucken! Währe eine Idee. Aber warum geht es dann mit allen Files die nicht n*1024 Bytes gross sind? Kennst du mmap? Ist die grössen Angabe gleich allozierter Speicher oder gelesene Bytes? Kann ich mmap mit tmpl_size+1 aufrufen und dann rawContent[ tmpl_size+1 ] = 0 machen?
Wo ist mein CompilerIch melde mich wenn ich's getestet habe!!
-
Aber warum geht es dann mit allen Files die nicht n*1024 Bytes gross sind?
Kennst du mmap?Aus der Manpage:
...
If len is not a multiple of the pagesize, the mapped region may extend past the
specified range. Any such extension beyond the end of the mapped object will be
zero-filled.
...Ist die grössen Angabe gleich allozierter Speicher oder gelesene Bytes?
Kann ich mmap mit tmpl_size+1 aufrufen und dann rawContent[ tmpl_size+1 ] = 0
machen?Mit der Groessenangabe legst du fest, wieviel Bytes der mapped-Memory
umfassen soll. Wenn du ein tmpl_size+1 reservierst, tritt automatisch
das o. zitierte Ereignis ein. Damit ist eine Angabe nicht mehr ein
vielfaches der Pagesize, womit der Bereich verlaengert wird und das was
hinter dem Ende kommt mit Nullen aufgefuellt wird.Wenn du unter Linux arbeitest, dann kannst du die Pagesize mittels der
getpagesize()-Funktion ermitteln. Sie ist in unistd.h definiert. Unter
BSD ist eine PAGE_SIZE-Konstante unter machine/param.h definiert. Du
kannst die Pagesize auch mittels sysctl -n hw.pagesize unter BSD erfragen.Du koenntest auch alternativ einfach mal im Programm einen Puffer deklarieren,
welcher 8193 Zeichen aufnehmen kann und kopierst rawContent dort hinein
(natuerlich Nullterminiert ;)). Dann machst du die Zuweisung.Aber ich bin mir fast sicher, dass es daran liegt, dass der Inhalt der
Datei im Speicher nicht Nullterminiert ist.mfg
v R
-
Peanut schrieb:
Wo gibt es den Verständnissprobleme?
Unbekannt:
#include <sys/mman.h> #include <sys/types.h> #include <fcntl.h> #include <sys/stat.h> struct stat st; open strerror mmap munmap
Ich nehme an das es sich hier um Compilerspezifische dinge handelt ?
Ich find zumindest nix dazu. Is ja aber auch wurscht, denke die Hilfe kam schon
-
Knuddlbaer schrieb:
Ich nehme an das es sich hier um Compilerspezifische dinge handelt?
Das ist Unix-spezifisch (POSIX).
-
Ahhhh jetzt ja
thx
-
virtuell Realisticer schrieb:
Aus der Manpage:
...
If len is not a multiple of the pagesize, the mapped region may extend past the
specified range. Any such extension beyond the end of the mapped object will be
zero-filled.
...Mit der Groessenangabe legst du fest, wieviel Bytes der mapped-Memory
umfassen soll. Wenn du ein tmpl_size+1 reservierst, tritt automatisch
das o. zitierte Ereignis ein. Damit ist eine Angabe nicht mehr ein
vielfaches der Pagesize, womit der Bereich verlaengert wird und das was
hinter dem Ende kommt mit Nullen aufgefuellt wird.Tja, wenn ich
rawContent = (char *)mmap(0, tmpl_size+1 , PROT_READ, MAP_SHARED, f, 0);
mache, bekomme ich einen "Bus-Zugriffsfehler"/"Bus error". Es hätte ja so schön sein können, ein Zeichen länger, Null wird aufgefüllt und zack.... naja, sollte halt nicht!
virtuell Realisticer schrieb:
Wenn du unter Linux arbeitest, dann kannst du die Pagesize mittels der
getpagesize()-Funktion ermitteln. Sie ist in unistd.h definiert.4096, ok mein Problem tritt also bei n*4096 Bytes im File auf,.... Hilft mit das weiter und ich weis nicht wie??
virtuell Realisticer schrieb:
Du koenntest auch alternativ einfach mal im Programm einen Puffer deklarieren,
welcher 8193 Zeichen aufnehmen kann und kopierst rawContent dort hinein
(natuerlich Nullterminiert ;)). Dann machst du die Zuweisung.Aber ich bin mir fast sicher, dass es daran liegt, dass der Inhalt der
Datei im Speicher nicht Nullterminiert ist.... char* rawContent; char* charmap; std::cout << getpagesize() << std::endl; f = open(filename.c_str(), O_RDONLY); if(f == -1) { throw (std::string)"Cannot open "+ filename + " Reason: " + strerror(errno); return 1; } if(fstat(f, &st) == -1) { throw (std::string)"Cannot stat " + filename + " Reason: " + strerror(errno); return 1; } int tmpl_size = st.st_size; rawContent = (char *)mmap(0, tmpl_size+1 , PROT_READ, MAP_SHARED, f, 0); charmap=(char*)malloc( tmpl_size + 1 ); strncpy( charmap, rawContent, tmpl_size ); charmap[ tmpl_size + 1 ]='\0'; // fileContent = rawContent; fileContent = charmap; ...
Jau, das tut es Jetzt ist noch die Frage ob ich nicht gleich über <iostream> einlese?
std::string tmp; while ( getline( f, tmp ) ){ fileContent += tmp + "\n"; }
-
Hallo,
das waere natuerlich jetzt eine andere Alternative, wenn du iostream nutzt. Aber
warum du jetzt einen Bus-Error bekommst ist mir aber schleierhaft. Der Quelltext
sieht m. E. korrekt aus.mfg
v R