Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 12

Discussione: Probabila bug di gcc?

  1. #1
    Utente di HTML.it L'avatar di 810106
    Registrato dal
    Jun 2008
    Messaggi
    67

    Probabila bug di gcc?

    Salve a tutti, sono qui con uno dei miei soliti dilemmi...

    Allora, implementando un albero binario bilanciato
    avevo scritto una funzione che mi rimuovesse un nodo, memorizzasse
    il suo indirizzo in un puntatore a puntatore passato come parametro
    e restituisse il suo nodo sinistro. Il problema è che questa funzione
    mi causava un bel SIGSEGV al suo ritorno poichè utilizzavo direttamente il
    valore restituito. Ora io ho risolto però vorrei capire se questo
    è un bug del mio compilatore o se è una cosa normale.
    Faccio un esempio per spiegare. Ecco una funzione che fa piu
    o meno quello che faceva la mia:

    codice:
    #include <stdlib.h>
    
    struct node
    {
      struct node *left, *right;
      void *data;
    };
    
    /* Salva un nodo in *node e ne restituisce un'altro */
    struct node *sigsegv(struct node **node)
    {
      struct node *__r;
      struct node *__n;
    
      /* Creo due nodi sullo heap */
    
      __n = malloc(sizeof(struct node));
      __n->left = NULL;
      __n->right = NULL;
      __n->data = NULL;
    
      __r = malloc(sizeof(struct node));
      __r->left = NULL;
      __r->right = NULL;
      __r->data = NULL;
    
      /* Mette l'indirizzo di __n in *node */
      *node = __n;
    
      /* Restituisce __r */
      return __r;
    }
    Ok ora la funzione main che utilizza la funzione definita,
    occhio alla chiamata:

    codice:
    int main( )
    {
      struct node *n = NULL;
      
      /*** In una chiamata alloca n e setta n->right ***/
      n->right = sigsegv(&n);
      
      return 0;
    }
    Esecuzione:

    codice:
    $ ./a.out
    Segmentation fault
    E subito il debugger:

    codice:
    $ gdb a.out
    GNU gdb 6.3
    Copyright 2004 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.
    ...
    (gdb) break main
    Breakpoint 1 at 0x80483ee: file testptr.c, line 28.
    (gdb) run
    Starting program: /home/._/a.out
    (gdb) step
    30        n->right = sigsegv(&n);
    (gdb) step
    sigsegv (node=0xbfa40b50) at testptr.c:14
    14        __n = malloc(sizeof(struct node));
    (gdb) step
    15        __n->right = NULL;
    (gdb) step
    16        __n->data = NULL;
    (gdb) step
    18        __r = malloc(sizeof(struct node));
    (gdb) step
    19        __r->right = NULL;
    (gdb) step
    20        __r->data = NULL;
    (gdb) step
    22        *node = __n;
    (gdb) step
    23        return __r;
    (gdb) print __r
    $1 = (struct node *) 0x804a060
    (gdb) print *__r
    $2 = {right = 0x0, data = 0x0}
    (gdb) print __n
    $3 = (struct node *) 0x804a050
    (gdb) print *__n
    $4 = {right = 0x0, data = 0x0}
    (gdb) step
    24      }
    (gdb) step
    
    Program received signal SIGSEGV, Segmentation fault.
    0x08048407 in main () at testptr.c:30
    30        n->right = sigsegv(&n);
    (gdb)
    In parole povere non posso fare n->right = sigsevg(&n)
    perchè al momento in cui la funzione ritorna n non è inizializzato.
    Ma se viene impostato dentro alla fnzione!?
    Ad esempio se io faccio

    codice:
    ...
      struct node *n = NULL, *right = NULL;
    
      right = sigsegv(&n);
      n->right = right;
    ...
    Funziona perfettamente. Qualcuno mi spiega perchè succede questo!?

    Grazie in anticipo! Christian.
    Free software: free as freedom!

  2. #2
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,466
    In effetti e' strano ... ho provato con Visual C++ e non da' alcun errore ...

    Prova ad ottenere il codice assembly relativo alla chiamata

    n->right = sigsegv(&n);

    (o anche di tutta la funzione se puoi ...) per dare un'occhiata piu' approfondita ...
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  3. #3
    A me sembra il fratello di

    http://c-faq.com/expr/evalorder1.html

    ;-)

    insomma non puoi sapere a priori se venga eseguita prima la "n->right" oppure la "sigsegv(&n)";

  4. #4
    Utente di HTML.it L'avatar di oregon
    Registrato dal
    Jul 2005
    residenza
    Roma
    Messaggi
    36,466
    Originariamente inviato da MacApp
    insomma non puoi sapere a priori se venga eseguita prima la "n->right" oppure la "sigsegv(&n)";
    Infatti ... ma volevo confrontare l'assembly generato con quello di VisualC++ ...
    No MP tecnici (non rispondo nemmeno!), usa il forum.

  5. #5
    Utente di HTML.it L'avatar di 810106
    Registrato dal
    Jun 2008
    Messaggi
    67

    :(

    Comunque ragazzi ho un gcc vecchio eh, probabilmente con uno nuovo questo non capita...
    Free software: free as freedom!

  6. #6
    codice:
    int main( )
    {
      struct node *n = NULL;
      
      /*** In una chiamata alloca n e setta n->right ***/
      n->right = sigsegv(&n);
      
      return 0;
    }
    può darsi che il compilatori valuti prima la sigsegv(&n) e allochi la memoria per n ed il compilatore non dia errore, ma resta comunque il fatto che scritto così è assolutamente sbagliato

  7. #7
    Utente di HTML.it L'avatar di 810106
    Registrato dal
    Jun 2008
    Messaggi
    67

    Codice ASM

    Ecco ho ottenuto il codice assembly generato dal comando gcc -S nomefile.c, non so se sia questo che intendete cmq eccolo:
    codice:
    	.file	"testptr.c"
    	.text
    .globl sigsegv
    	.type	sigsegv, @function
    sigsegv:
    	pushl	%ebp
    	movl	%esp, %ebp
    	subl	$8, %esp
    	subl	$12, %esp
    	pushl	$8
    	call	malloc
    	addl	$16, %esp
    	movl	%eax, -8(%ebp)
    	movl	-8(%ebp), %eax
    	movl	$0, (%eax)
    	movl	-8(%ebp), %eax
    	movl	$0, 4(%eax)
    	subl	$12, %esp
    	pushl	$8
    	call	malloc
    	addl	$16, %esp
    	movl	%eax, -4(%ebp)
    	movl	-4(%ebp), %eax
    	movl	$0, (%eax)
    	movl	-4(%ebp), %eax
    	movl	$0, 4(%eax)
    	movl	8(%ebp), %edx
    	movl	-8(%ebp), %eax
    	movl	%eax, (%edx)
    	movl	-4(%ebp), %eax
    	leave
    	ret
    	.size	sigsegv, .-sigsegv
    .globl main
    	.type	main, @function
    main:
    	pushl	%ebp
    	movl	%esp, %ebp
    	pushl	%ebx
    	subl	$4, %esp
    	andl	$-16, %esp
    	movl	$0, %eax
    	subl	%eax, %esp
    	movl	$0, -8(%ebp)
    	movl	-8(%ebp), %ebx
    	subl	$12, %esp
    	leal	-8(%ebp), %eax
    	pushl	%eax
    	call	sigsegv
    	addl	$16, %esp
    	movl	%eax, (%ebx)
    	movl	$0, %eax
    	movl	-4(%ebp), %ebx
    	leave
    	ret
    	.size	main, .-main
    	.section	.note.GNU-stack,"",@progbits
    	.ident	"GCC: (GNU) 3.3.4"
    Si vede anche che è una versione stravecchia di gcc (3.3.4), appena posso compilo gcc 4 e vi so dire se anche su quello succede...
    Free software: free as freedom!

  8. #8
    Utente di HTML.it L'avatar di 810106
    Registrato dal
    Jun 2008
    Messaggi
    67
    Originariamente inviato da mondobimbi
    codice:
    int main( )
    {
      struct node *n = NULL;
      
      /*** In una chiamata alloca n e setta n->right ***/
      n->right = sigsegv(&n);
      
      return 0;
    }
    può darsi che il compilatori valuti prima la sigsegv(&n) e allochi la memoria per n ed il compilatore non dia errore, ma resta comunque il fatto che scritto così è assolutamente sbagliato
    Scusa mi spieghi che c'è di sbagliato, è chiaro cosa voglio che faccia la funzione, e lo deve fare punto e basta!
    Free software: free as freedom!

  9. #9
    sì, però prima della chiamata alla funzione richiami un membro di una struttura che è NULL, quindi chiaramente hai un errore di runtime.
    Siccome la specifica del C non dice niente riguardo all'ordine di esecuzione può essere (ma non definito) che il compilatore valuti prima la funzione, allocando quindi la memoria per la struttura e poi richiamando il membro right, ed il questo caso non c'è errore di runtime, ma comunque il tuo codice rimane sbagliato.
    ciao
    sergio

  10. #10
    Utente di HTML.it L'avatar di 810106
    Registrato dal
    Jun 2008
    Messaggi
    67

    Scusate ma...

    codice:
      n->right = sigsegv(&n);
    /* EXPR    =   EXPR */
    Giusto? quindi non si sa se il compilatore valuta per prima l'espressione a dx o a sx... beh credo che sia possibile, però è strano cavolo, nessuno ci ha pensato quando è stato scritto il C? cosi sono costretto ad usare un puntatore temporaneo...
    Free software: free as freedom!

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.