Gelöst: memmove und Segementation Fault



  • Hallo,

    ich habe noch nicht die größten Kenntnisse in C.
    Ich habe ein kleines Programm geschrieben das auf einem 32-Bit System (RaspberryPi2) ohne äußerlich erkennbare Fehler läuft.

    Dieser Teil sollte über die serielle Schnittstelle empfangene Zeichen an einen bestimmten Buffer anhängen.

    Beim test auf einem 64-Bit System habe ich feststellen müssen dass ich da irgendwas grundlegend falsch mache. Das Programm bricht immer mit "Segmentation Fault" wenn es in diesen Programmbereich kommt. Leider habe ich keine Ahnung was das Problem ist.

    char bufferSwb[20000];
    	int bufferSwbCount=0;
    	int bytesSwb=0;
    
    if (serialBytes>0) {
      /* create temporary buffer for received Bytes */
      int tmpBuffer[serialBytes];
      bytesSwb = read(fdSwb, &tmpBuffer, sizeof(tmpBuffer));
      if (bytesSwb<0) {
        perror("read(Swb)");
      }
      if (bytesSwb>0) {
        printf("bufferSwb : %d\n", sizeof(bufferSwb) / sizeof(char));
        printf("bufferSwbCount : %d\n", bufferSwbCount);
        printf("tmpBuffer : %d\n", sizeof(tmpBuffer) / sizeof(char));
        printf("bytesSwb : %d\n", bytesSwb);
        memmove(bufferSwb+bufferSwbCount, tmpBuffer, bytesSwb);
        bufferSwbCount+=bytesSwb;
      }
        .
        .
        .
    }
    

    als Ausgabe bekomme ich folgendes:

    bufferSwb : 20000
    bufferSwbCount : 0
    tmpBuffer : 4
    bytesSwb : 1
    Segmentation fault
    

    Irgendwie komme ich da im Moment nicht weiter...



  • Bist du sicher, dass der Fehler an dieser Stelle auftritt? Eigentlich sollte es in diesem Fall nicht crashen (aber du hast eventuell eine Sicherheitsluecke drin!).

    Wenn du das Programm z.B. mit GDB startest siehst du genau an welcher Stelle der Segmentation Fault auftritt. Alternativ kannst du einfach mal alles Auskommentieren und dann schrittweise Code reinnehmen, bis es crasht. Dann hast du sofort die Zeile, in der das Problem auftritt. Ist etwas hacky aber meistens sehr effektiv.



  • Der Code ist grottenschlecht.
    Nur Deppen benutzen VLA.
    memmove ist hier die falsche Wahl, was hast du dir dabei gedacht?
    Nutze valgrind für solche Fehler.



  • icarus2 schrieb:

    Bist du sicher, dass der Fehler an dieser Stelle auftritt? Eigentlich sollte es in diesem Fall nicht crashen

    Eigentlich schon. Hatte versucht mit GDB zu debuggen. GDB will aber keine Threads(?).

    Habe dann durch auskommentieren es auf diesen Befehl eingrenzen können. Ist er auskommentiert bekomme ich nicht den Fehler.

    Wutz schrieb:

    Der Code ist grottenschlecht.
    Nur Deppen benutzen VLA.
    memmove ist hier die falsche Wahl, was hast du dir dabei gedacht?
    Nutze valgrind für solche Fehler.

    Werde mich mal mit Valgrind beschäftigen.

    Dachte memmove wäre hierfür OK. Warum ist memmove denn die falsche Wahl?

    Ist es besser jedesmal ein 200 Byte-Array zu nehmen wenn zu 90 Prozent nur zwischen 1 und 10 Bytes benötigt werden?

    Habe für tmpBuffer ein festes Array mit 200 Char genommen. Am Fehler hat sich nichts geändert.



  • Hallo,

    ich habe memmove rausgenommen. Jetzt funktioniert es.
    Habe allerdings absolut keine Ahnung was jetzt der Unterschied zu memmove ist.

    valgrind kann ich auf der Diskstation nicht installieren (gibt noch keine toolchain für DSM6.1)

    Warum memmove die falsche Wahl ist ist mir bisher unbekannt.
    Vielleicht weil memcpy gereicht hätte?
    Hätte ich lieber strncpy nehmen sollen?

    Bringen aber alle den selben Fehler...

    Habe memmove durch einen Code ersetzt und es scheint zu funktionieren:

    int bytesSwb=0;
    int bufferSwbCount=0;
    unsigned char bufferSwb[50];
    
    if (serialBytes>0) {
    	if ((actualSwbTimeout>=0)&&(bufferSwbCount>=0)) {
    		/* start receiving and reset timeout */
    		actualSwbTimeout=serialSwbWait;
    	}
    	/* create temporary buffer for received Bytes */
    	bytesSwb = read(fdSwb, &tmpBuffer, serialBytes);
    	if (bytesSwb<0) {
    		perror("read(Swb)");
    	}
    	if (bytesSwb<=0) {
    		actualSwbTimeout--;
    	}
    		if (bytesSwb>0) {
    		for (loop2=0;loop2<bytesSwb;loop2++) {
    			bufferSwb[bufferSwbCount+loop2]=tmpBuffer[loop2];
    		}
    		bufferSwbCount+=bytesSwb;
    	}
    }
    

    Was ist denn der kleine feine Unterschied zu den Funktionen?
    Wie kann ich meinen "grottenschlechten" codeschnipsel denn besser machen 😕



  • Habe mal valgrind auf meinem Raspberry Pi2 laufen lassen und es wurden keine Fehler gefunden. Das Programm läuft dort ohne Abstürze.

    Auf meiner Diskstation sieht es ganz anders aus. Dann habe ich mal ein kleines Testprogramm geschrieben:

    #include <stdio.h>	
    #include <string.h>
    
    int main( int argc, char* argv[] ) {
    	printf(".");
    	char string[] = {"Ein Teststring mit Worten"};
    	printf(".");
    	printf("%s\n",strchr(string, (int)'W'));
    	printf(".");
    	printf("%s\n",strchr(string, (int)'T'));
    	printf(".");
    	return 0;
    }
    

    Läuft auf dem RaspberryPi2 wie erwartet. Auf der Diskstation läuft nicht:

    root@DS1815:/volume1/public/test/prog# gcc -g -Wall -o prog prog.c
    root@DS1815:/volume1/public/test/prog# ./prog
    Segmentation fault (core dumped)
    root@DS1815:/volume1/public/test/prog# sudo ./prog
    Segmentation fault
    root@DS1815:/volume1/public/test/prog# gdb ./prog

    dlopen failed on 'libthread_db.so.1' - libthread_db.so.1: cannot open shared object file: No such file or directory
    GDB will not be able to debug pthreads.

    GNU gdb 6.8
    Copyright (C) 2008 Free Software Foundation, Inc.
    License GPLv3+: GNU GPL version 3 or later http://gnu.org/licenses/gpl.html
    This is free software: you are free to change and redistribute it.
    There is NO WARRANTY, to the extent permitted by law. Type "show copying"
    and "show warranty" for details.
    This GDB was configured as "i686-linux-gnu"...
    (gdb) run
    Starting program: /volume1/public/test/prog/prog
    Error while mapping shared library sections:
    linux-gate.so.1: No such file or directory.
    BFD: /usr/lib32/libc.so.6: invalid relocation type 42
    BFD: BFD (GNU Binutils) 2.18.50.20080226 assertion fail elf32-i386.c:366
    BFD: /usr/lib32/libc.so.6: invalid relocation type 42
    BFD: BFD (GNU Binutils) 2.18.50.20080226 assertion fail elf32-i386.c:366
    BFD: /usr/lib32/libc.so.6: invalid relocation type 42
    BFD: BFD (GNU Binutils) 2.18.50.20080226 assertion fail elf32-i386.c:366
    BFD: /usr/lib32/libc.so.6: invalid relocation type 42
    BFD: BFD (GNU Binutils) 2.18.50.20080226 assertion fail elf32-i386.c:366

    Program received signal SIGSEGV, Segmentation fault.
    0x08049690 in strchr@@GLIBC_2.0 ()
    (gdb) q
    The program is running. Exit anyway? (y or n) y
    root@DS1815:/volume1/public/test/prog#

    Hat jemand eine Idee was dort falsch läuft 😕



  • Welche Version des gcc und der glibc ist dort denn installiert?

    Bei Ideone (laut Tooltip gcc 6.3) läuft dein Code natürlich...

    PS: Wenn du wirklich dort GLIBC_2.0 hast, dann ist dieser sehr alt: GNU-C-Bibliothek: Versionsgeschichte



  • Hatte gerade noch ein Update installiert. Hat aber nichts am Problem geändert.

    Diskstation:
    GCC: 4.2.1
    LIBC: 2.20-2014-11

    RaspberryPi2:
    GCC: 4.8.4
    LIBC: 2.19



  • Das Pkompilieren ist auf der Diskstation nicht mehr wirklich möglich.

    Mit Crosscompiling klappt alles so wie es soll.


Log in to reply