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 Compiler 😕

    Ich 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


Log in to reply