PDA

Visualizza versione completa : [C] Segmentation fault


Manugal
28-03-2006, 18.42.24
Ciao!!!

Sono settimane che questo problema mi tormenta. Sto facendo un progetto per l'Università che dovrò cosnegnare il 3 aprile. Ho fatto tutto, ma c'è questo segmentation fault che non ne vuole sapere di sparire. Allora praticamente mi hanno fornito un file di Test il quale appunto testerà la mia funzione e ad un test di questi mi dà l'errore. Ora posto la mia funzione (per intero) e poi il codice del test in questione:


#include "LPC_M1_Include.h"
#include "LPC_Include.h"
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>

int CreateDatabaseFile(char *Name, int NumFields, FIELD_DATA_t *FieldData){
int i;
header *h;
h=(header *)malloc(sizeof(header));
if((Name==NULL) || cercaErr(Name) || (NumFields<=0) || (NumFields>MAX_NUM_FIELDS)){
char Err[256];
(void) sprintf(Err, "Nome DB nullo o non valido o NumFields<=0");
LPC_GestioneErrore(LPC_BAD_ARG, "CreateDatabaseFile", Err);
if(h!=NULL)
free(h);
return LPC_BAD_ARG;
}
if(FieldData==NULL){
char Err[256];
(void) sprintf(Err, "Errore allocazione memoria");
LPC_GestioneErrore(LPC_NO_MEMORY, "CreateDatabaseFile", Err);
if(h!=NULL)
free(h);
return LPC_NO_MEMORY;
}
if(strlen(Name)>DBF_NAME_LENGTH+1)
Name[DBF_NAME_LENGTH+1]='\0';
strcat(Name,DBF_EXTENSION);
FILE *fp=fopen(Name,"wb+");
if(fp==NULL){
char Err[256];
(void) sprintf(Err, "Errore allocazione memoria");
LPC_GestioneErrore(LPC_NO_MEMORY, "CreateDatabaseFile", Err);
if(h!=NULL)
free(h);
return LPC_NO_MEMORY;
}
h->NumCampi=(uint16_t) htons(h->NumCampi);
h->NumCampi=NumFields;
h->NumRecords=(uint32_t) htonl(h->NumRecords);
h->NumRecords=0;
h->dimHeader=(uint16_t) htons(h->dimHeader);
h->dimHeader=DBF_FIXED_HEADER_LEN+NumFields*(DBF_FIEL D_LEN+NumFields)+2;
h->dimRecord=(uint16_t) htons(h->dimRecord);
h->dimRecord=0;
h->timestamp=(uint32_t) htonl(h->timestamp);
h->timestamp=time(NULL);
for(i=0; i<NumFields; ++i){
if(FieldData[i].Name==NULL){
char Err[256];
(void) sprintf(Err, "Valore di uno dei campi non valido: nome, tipo o lunghezza");
LPC_GestioneErrore(LPC_BAD_FIELD, "CreateDatabaseFile", Err);
if(h!=NULL)
free(h);
return LPC_BAD_FIELD;
}
if((cercaErr(FieldData[i].Name)) || (StringaUguale(FieldData[i].Name,h,i))){
char Err[256];
(void) sprintf(Err, "Valore di uno dei campi non valido: nome, tipo o lunghezza");
LPC_GestioneErrore(LPC_BAD_FIELD, "CreateDatabaseFile", Err);
if(h!=NULL)
free(h);
return LPC_BAD_FIELD;
}
strcpy(h->campo[i].name,FieldData[i].Name);
if ((FieldData[i].FieldType!=CHARACTER) || (FieldData[i].FieldType!=NUMERIC) || (FieldData[i].FieldType!=DATE) || (FieldData[i].FieldType!=LOGICAL)){
char Err[256];
(void) sprintf(Err, "Valore di uno dei campi non valido: nome, tipo o lunghezza");
LPC_GestioneErrore(LPC_BAD_FIELD, "CreateDatabaseFile", Err);
if(h!=NULL)
free(h);
return LPC_BAD_FIELD;
}
h->campo[i].fieldtype=(uint16_t) htons(h->campo[i].fieldtype);
h->campo[i].fieldtype=FieldData[i].FieldType;
h->campo[i].fieldlen=(uint16_t) htons(h->campo[i].fieldlen);
if((h->campo[i].fieldtype==CHARACTER) && ((FieldData[i].FieldLen>=1) && (FieldData[i].FieldLen<=FIELD_CHAR_LEN)))
h->campo[i].fieldlen=FieldData[i].FieldLen;
if((h->campo[i].fieldtype==NUMERIC) && (FieldData[i].FieldLen<=FIELD_NUM_LEN))
h->campo[i].fieldlen=FieldData[i].FieldLen;
if((h->campo[i].fieldtype==DATE) && (FieldData[i].FieldLen<=FIELD_DATE_LEN))
h->campo[i].fieldlen=FieldData[i].FieldLen;
if((h->campo[i].fieldtype==LOGICAL) && (FieldData[i].FieldLen<=FIELD_LOGI_LEN))
h->campo[i].fieldlen=FieldData[i].FieldLen;
h->dimRecord+=(h->campo[i].fieldlen+1);
}
int ret=fwrite(h,sizeof(h),1,fp);
if(ret!=h->dimHeader){
char Err[256];
(void) sprintf(Err, "Errore di sistema [%d] in scrittura su file: [%s]", errno, strerror(errno));
LPC_GestioneErrore(LPC_ERR_WRITE, "CreateDatabaseFile", Err);
if(h!=NULL)
free(h);
return LPC_ERR_WRITE;
}
fclose(fp);
return LPC_OK;
putchar('\n');
}


TEST

#define MAX_TEST 100
typedef struct {
int testid;
int weight;
char desc[256];
int passed;
} TEST_t;

static int numtest;
static TEST_t test[MAX_TEST];

int ret= 0;
int NumFields = 0;
FILE *fp;
FIELD_DATA_t FieldData[MAX_NUM_FIELDS];
int len, len1;
char buf[500], buftest[500];

printf("Test CREATE\n");
...
...
...
// Campo non valido
/*** Test del Nome, Tipo, Lunghezza *****/
test[numtest].testid = 10107;
test[numtest].weight = 1;
strcpy(test[numtest].desc, "CREATE: Nome campo non valido");
printf("Test:[%d] Peso:[%d] - [%s]\n", test[numtest].testid, test[numtest].weight,test[numtest].desc);
NumFields = 1;
strcpy(FieldData[0].Name, "_Campo1");
FieldData[0].FieldType = CHARACTER;
FieldData[0].FieldLen = 10;
ret = CreateDatabaseFile("Prova", NumFields, FieldData);
printf("Ritorno della create: [%d]\n\n", ret);
if (ret != LPC_OK)
test[numtest].passed = 1;
numtest++;

test[numtest].testid = 10108;
test[numtest].weight = 3;
strcpy(test[numtest].desc, "CREATE: Tipo campo non valido");
printf("Test:[%d] Peso:[%d] - [%s]\n", test[numtest].testid, test[numtest].weight,test[numtest].desc);
NumFields = 1;
strcpy(FieldData[0].Name, "Campo1");
FieldData[0].FieldType = 15;
FieldData[0].FieldLen = 10;
ret = CreateDatabaseFile("Prova", NumFields, FieldData);
printf("Ritorno della create: [%d]\n\n", ret);
if (ret != LPC_OK)
test[numtest].passed = 1;
numtest++;

test[numtest].testid = 10109;
test[numtest].weight = 2;
strcpy(test[numtest].desc, "CREATE: Lunghezza campo non valida");
printf("Test:[%d] Peso:[%d] - [%s]\n", test[numtest].testid, test[numtest].weight,test[numtest].desc);
NumFields = 1;
strcpy(FieldData[0].Name, "Campo1");
FieldData[0].FieldType = CHARACTER;
FieldData[0].FieldLen = FIELD_CHAR_LEN+1;
ret = CreateDatabaseFile("Prova", NumFields, FieldData);
printf("Ritorno della create: [%d]\n\n", ret);
if (ret != LPC_OK)
test[numtest].passed = 1;
numtest++;

test[numtest].testid = 10110;
test[numtest].weight = 2;
strcpy(test[numtest].desc, "CREATE: Campo gia' esistente");
printf("Test:[%d] Peso:[%d] - [%s]\n", test[numtest].testid, test[numtest].weight,test[numtest].desc);
NumFields = 2;
strcpy(FieldData[0].Name, "Campo1");
FieldData[0].FieldType = CHARACTER;
FieldData[0].FieldLen = 10;
strcpy(FieldData[1].Name, "Campo1");
FieldData[1].FieldType = CHARACTER;
FieldData[1].FieldLen = 10;
ret = CreateDatabaseFile("Prova", NumFields, FieldData);
printf("Ritorno della create: [%d]\n\n", ret);
if (ret != LPC_OK)
test[numtest].passed = 1;
numtest++;



Vi prego non so più a che santo appellarmi :( :(

Manugal
29-03-2006, 06.54.41
Nessuno??? :(

quipo.it
29-03-2006, 09.12.28
com'è definito header?

Perché dichiari "char Err[256];" all'interno dei blocchi if()?

Hai provato ad usare un memory debugger tipo valgrind? O anche solo gdb?

Manugal
29-03-2006, 16.48.40
Purtroppo non è che sappia usarli bene, comunque se ti va di provarlo l'ho uppato su Rapidshare. Dichiaro char err[256] dentro gli if perché le specifiche che mi hanno dato lo richiedono.

http://rapidshare.de/files/16712699/DBF.tar.gz.html

Lo estrai e per compilarlo vai nella cartella Modulo1 e digita make test. Per eseguire poi i test, una volta compilato, vai nella cartella test (sempre dentro Modulo1) e lanci TestM1.

Grazie. :)

Manugal
29-03-2006, 17.06.22
Mi sono un po' imparato ad usare valgrind(). Ecco il risultato facendo un --leack-check=full



==17259==
==17259== Process terminating with default action of signal 11 (SIGSEGV)
==17259== Bad permissions for mapped region at address 0x804B3FD
==17259== at 0x401C481: strcat (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==17259== by 0x804A86D: CreateDatabaseFile (LPC_CreateDBF.c:32)
==17259== by 0x8049354: TestCreate (TestM1.c:201)
==17259== by 0x8048AF2: main (TestM1.c:94)
==17259==
==17259== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 11 from 1)
==17259== malloc/free: in use at exit: 4,108 bytes in 1 blocks.
==17259== malloc/free: 7 allocs, 6 frees, 28,756 bytes allocated.
==17259== For counts of detected errors, rerun with: -v
==17259== searching for pointers to 1 not-freed blocks.
==17259== checked 86,372 bytes.
==17259==
==17259== LEAK SUMMARY:
==17259== definitely lost: 0 bytes in 0 blocks.
==17259== possibly lost: 0 bytes in 0 blocks.
==17259== still reachable: 4,108 bytes in 1 blocks.
==17259== suppressed: 0 bytes in 0 blocks.
==17259== Reachable blocks (those to which a pointer was found) are not shown.
==17259== To see them, rerun with: --show-reachable=yes
Segmentation fault

quipo.it
29-03-2006, 17.06.59
Modulo1 è vuota...

Manugal
29-03-2006, 17.19.27
accidenti hai ragione perché ti ho mandato solo la struttura delle directory. Aspetta allora che riuppo tutto.

Manugal
29-03-2006, 17.26.25
http://rapidshare.de/files/16715758/DBF.tar.gz.html

Eccolo qua corretto! :)

Manugal
29-03-2006, 17.46.35
Sono riuscito a togliere un Segmentation Fault, adesso però me lo dà sull'ultimo test. :( (Grazie a valgrind sono riuscito a scovarlo)

Questo è l'output di valgrind per quest'ultimo errore (e qui non riesco a scovarlo):



Test:[10113] Peso:[10] - [CREATE: Verifica correttezza]
==17837==
==17837== Invalid read of size 4
==17837== at 0x408E77E: fread (in /lib/tls/libc-2.3.5.so)
==17837== by 0x8049C97: TestCreate (TestM1.c:316)
==17837== by 0x8048AF2: main (TestM1.c:94)
==17837== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==17837==
==17837== Process terminating with default action of signal 11 (SIGSEGV)
==17837== Access not within mapped region at address 0x0
==17837== at 0x408E77E: fread (in /lib/tls/libc-2.3.5.so)
==17837== by 0x8049C97: TestCreate (TestM1.c:316)
==17837== by 0x8048AF2: main (TestM1.c:94)
==17837==
==17837== ERROR SUMMARY: 16 errors from 16 contexts (suppressed: 11 from 1)
==17837== malloc/free: in use at exit: 2,112 bytes in 6 blocks.
==17837== malloc/free: 21 allocs, 15 frees, 52,464 bytes allocated.
==17837== For counts of detected errors, rerun with: -v
==17837== searching for pointers to 6 not-freed blocks.
==17837== checked 87,372 bytes.
==17837==
==17837==
==17837== 2,112 bytes in 6 blocks are still reachable in loss record 1 of 1
==17837== at 0x401A43A: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==17837== by 0x408E21E: __fopen_internal (in /lib/tls/libc-2.3.5.so)
==17837== by 0x408E2DC: fopen@@GLIBC_2.1 (in /lib/tls/libc-2.3.5.so)
==17837== by 0x804A86D: CreateDatabaseFile (LPC_CreateDBF.c:32)
==17837== by 0x8049354: TestCreate (TestM1.c:201)
==17837== by 0x8048AF2: main (TestM1.c:94)
==17837==
==17837== LEAK SUMMARY:
==17837== definitely lost: 0 bytes in 0 blocks.
==17837== possibly lost: 0 bytes in 0 blocks.
==17837== still reachable: 2,112 bytes in 6 blocks.
==17837== suppressed: 0 bytes in 0 blocks.
Segmentation fault

quipo.it
29-03-2006, 18.02.20
ho guardato il makefile, non hai impostato i warning:

CCFLAGS= -c $(DEBUG) -Wall

sono molto utili per scoprire problemi in fase di compilazione.
Vedo ad esempio alcuni errori di confronto tra signed e unsigned int.

Io poi di solito uso g++ come compiler:

CC=g++


Il makefile non compila il file contenente LPC_GestioneErrore()

In LPC_CreateDBF.c non hai dichiarato la variabile tmp, e probabilmente devi assegnarle il risultato di strcat()


In TestM1.c non fai nessun controllo sull'apertura dei files:

LINE 311:

fp = fopen("Prova.dbf", "r");
if (fp == NULL) {
//oops...
exit(EXIT_FAILURE);
}

Manugal
29-03-2006, 18.08.34
Il Makefile e TestM1 non li ho fatti io ma me li hanno dati i miei professori e dicono che sono funzionanti e testati. Io ho creato solamente quello che c'è nella cartella src.

quipo.it
29-03-2006, 18.58.48
sarà, però mancano tutti i controlli...


comunque: il segfault è in LPC_CreateDBF.c, nella riga che ti ho suggerito sopra: stai cercando di aprire un file il cui nome è contenuto nella variabile tmp, che non è definita. Inoltre ci dev'essere qualche problema nella strcat() alla riga 36, sostituiscila con questo codice:


//dichiarazioni
char *filename;
int newlen;

//linea 36
newlen = strlen(Name) + strlen(DBF_EXTENSION) + 1;
filename = (char *)malloc(sizeof(char) * newlen);
sprintf(filename, "%s%s", Name, DBF_EXTENSION);

FILE *fp=fopen(filename,"wb+"); // <== "filename", non "tmp"!!!

quipo.it
29-03-2006, 19.02.11
ricordati: gdb è il tuo migliore amico:

$ gdb Test1

r (run)



inoltre, mandami l'output del test. Qui mi da' molti errori... sono voluti?

Perché non usate una testsuite tipo CUNIT?

Manugal
29-03-2006, 19.03.46
Grazie, ma quel problema come avevo scritto poco fa l'avevo risolto (a dire la verità neanche mi serviva aggiungere l'espressione lì). Il problema è ora nell'ultimo test. valgrind mi da questo output:


Test:[10113] Peso:[10] - [CREATE: Verifica correttezza]
==17837==
==17837== Invalid read of size 4
==17837== at 0x408E77E: fread (in /lib/tls/libc-2.3.5.so)
==17837== by 0x8049C97: TestCreate (TestM1.c:316)
==17837== by 0x8048AF2: main (TestM1.c:94)
==17837== Address 0x0 is not stack'd, malloc'd or (recently) free'd
==17837==
==17837== Process terminating with default action of signal 11 (SIGSEGV)
==17837== Access not within mapped region at address 0x0
==17837== at 0x408E77E: fread (in /lib/tls/libc-2.3.5.so)
==17837== by 0x8049C97: TestCreate (TestM1.c:316)
==17837== by 0x8048AF2: main (TestM1.c:94)
==17837==
==17837== ERROR SUMMARY: 16 errors from 16 contexts (suppressed: 11 from 1)
==17837== malloc/free: in use at exit: 2,112 bytes in 6 blocks.
==17837== malloc/free: 21 allocs, 15 frees, 52,464 bytes allocated.
==17837== For counts of detected errors, rerun with: -v
==17837== searching for pointers to 6 not-freed blocks.
==17837== checked 87,372 bytes.
==17837==
==17837==
==17837== 2,112 bytes in 6 blocks are still reachable in loss record 1 of 1
==17837== at 0x401A43A: malloc (in /usr/lib/valgrind/x86-linux/vgpreload_memcheck.so)
==17837== by 0x408E21E: __fopen_internal (in /lib/tls/libc-2.3.5.so)
==17837== by 0x408E2DC: fopen@@GLIBC_2.1 (in /lib/tls/libc-2.3.5.so)
==17837== by 0x804A86D: CreateDatabaseFile (LPC_CreateDBF.c:32)
==17837== by 0x8049354: TestCreate (TestM1.c:201)
==17837== by 0x8048AF2: main (TestM1.c:94)
==17837==
==17837== LEAK SUMMARY:
==17837== definitely lost: 0 bytes in 0 blocks.
==17837== possibly lost: 0 bytes in 0 blocks.
==17837== still reachable: 2,112 bytes in 6 blocks.
==17837== suppressed: 0 bytes in 0 blocks.
Segmentation fault

Manugal
29-03-2006, 19.05.11
Gli errori non lo so se sono voluti sinceramente. Io ho programmato secondo le specifiche (spero di averlo fatto decentemente :) ).

Manugal
29-03-2006, 19.06.28
Questo è l'output di gdb invece:



Program received signal SIGSEGV, Segmentation fault.
0x4008677e in fread () from /lib/tls/libc.so.6



Ma questa fread non l'ho mai usata??!?!!

Manugal
29-03-2006, 19.11.10
No non ci credo. Aggiungendo quelle linee mi finisce tutti i test. Però sinceramente non capisco perché gli ultimi due test mi dice che non li ho passati. Come mai?

quipo.it
29-03-2006, 19.19.10
hai anche dimenticato una malloc:

in LPC_DeleteDBF.c, LINE 21:

tmp = (char *)malloc(sizeof(char) * (strlen(Name) + 1));

va inserita prima della

strcpy(tmp,Name);

Manugal
29-03-2006, 19.25.11
Grazie. Senti mi sapresti dire perché nei test mi ritorna un valore invece che un altro? Ad esempio nel test che controlla se un campo è valido mi ritorna DBF esistente, mentre io gli ho detto di tornare esplicitamente Nome campo o tipo non valido qualcosa del genere.

quipo.it
29-03-2006, 19.31.15
Dove?

Questo è l'output sulla mia macchina:


Test CREATE
Test:[10101] Peso:[3] - [CREATE: nome NULL]
Errore [-1] in [CreateDatabaseFile]-->[Nome DB nullo o non valido o NumFields<=0]
Ritorno della create: [-1]

Test:[10102] Peso:[1] - [CREATE: nome non valido]
Errore [-1] in [CreateDatabaseFile]-->[Nome DB nullo o non valido o NumFields<=0]
Ritorno della create: [-1]

Test:[10103] Peso:[1] - [CREATE [%d]: nome non valido (2)]
Errore [-1] in [CreateDatabaseFile]-->[Nome DB nullo o non valido o NumFields<=0]
Ritorno della create: [-1]

Test:[10104] Peso:[3] - [CREATE: NumFields nonvalido]
Errore [-1] in [CreateDatabaseFile]-->[Nome DB nullo o non valido o NumFields<=0]
Ritorno della create: [-1]

Test:[10105] Peso:[3] - [CREATE: NumFields nonvalido (2)]
Errore [-1] in [CreateDatabaseFile]-->[Nome DB nullo o non valido o NumFields<=0]
Ritorno della create: [-1]

Test:[10106] Peso:[3] - [CREATE: FieldData nonvalido]
Errore [-8] in [CreateDatabaseFile]-->[Errore allocazione memoria]
Ritorno della create: [-8]

Test:[10107] Peso:[1] - [CREATE: Nome campo non valido]
Errore [-2] in [CreateDatabaseFile]-->[Valore di uno dei campi non valido: nome, tipo o lunghezza]
Ritorno della create: [-2]

Test:[10108] Peso:[3] - [CREATE: Tipo campo non valido]
Errore [-2] in [CreateDatabaseFile]-->[Valore di uno dei campi non valido: nome, tipo o lunghezza]
Ritorno della create: [-2]

Test:[10109] Peso:[2] - [CREATE: Lunghezza campo non valida]
Errore [-2] in [CreateDatabaseFile]-->[Valore di uno dei campi non valido: nome, tipo o lunghezza]
Ritorno della create: [-2]

Test:[10110] Peso:[2] - [CREATE: Campo gia' esistente]
Errore [-2] in [CreateDatabaseFile]-->[Valore di uno dei campi non valido: nome, tipo o lunghezza]
Ritorno della create: [-2]

Test:[10111] Peso:[4] - [CREATE: DBF esistente]
Errore [-2] in [CreateDatabaseFile]-->[Valore di uno dei campi non valido: nome, tipo o lunghezza]
Ritorno della create: [-2]

Test:[10112] Peso:[10] - [CREATE: Funzionalita']
Errore [-2] in [CreateDatabaseFile]-->[Valore di uno dei campi non valido: nome, tipo o lunghezza]
Ritorno della create: [-2]
Test:[10113] Peso:[10] - [CREATE: Verifica correttezza]

ID: 10101 10102 10103 10104 10105 10106 10107 10108 10109 10110 10111 10112 10113
PESO: 3 1 1 3 3 3 1 3 2 2 4 10 10
PASS: 1 1 1 1 1 1 1 1 1 1 1 0 0

Fine Test [CREATE]: Numtests:[13] Totvalue:[46] Passed:[26] Score:[56.52]

Test DELETE
Test:[10201] Peso:[2] - [DELETE: nome NULL]
Errore [-1] in [DeleteDatabaseFile]-->[Nome DB nullo o non valido]
Ritorno della delete: [-1]

Test:[10202] Peso:[1] - [DELETE: nome non valido]
Errore [-1] in [DeleteDatabaseFile]-->[Nome DB nullo o non valido]
Ritorno della delete: [-1]

Test:[10203] Peso:[1] - [DELETE: nome non valido (2)]
Errore [-1] in [DeleteDatabaseFile]-->[Nome DB nullo o non valido]
Ritorno della delete: [-1]

Test:[10204] Peso:[2] - [Test DELETE: DBF non esistente]
Errore [-4] in [DeleteDatabaseFile]-->[Il file non esiste o non può essere cancellato]
Ritorno della delete: [-4]

Test:[10205] Peso:[3] - [Test DELETE: DBF aperto
]
Errore [-10] in [DeleteDatabaseFile]-->[Il database è aperto]
Ritorno della delete: [-10]

Test:[10206] Peso:[10] - [Test DELETE: Funzionalita']
Errore [-4] in [DeleteDatabaseFile]-->[Il file non esiste o non può essere cancellato]
Ritorno della Delete: [-4]

ID: 10101 10102 10103 10104 10105 10106 10107 10108 10109 10110 10111 10112 10113 10201 10202 10203 10204 10205 10206
PESO: 3 1 1 3 3 3 1 3 2 2 4 10 10 2 1 1 2 3 10
PASS: 1 1 1 1 1 1 1 1 1 1 1 0 0 1 1 1 1 1 0

Fine Test [DELETE]: Numtests:[19] Totvalue:[65] Passed:[35] Score:[53.85]

Manugal
29-03-2006, 19.34.33
Test:[10111] Peso:[4] - [CREATE: DBF esistente]
Errore [-2] in [CreateDatabaseFile]-->[Valore di uno dei campi non valido: nome, tipo o lunghezza]
Ritorno della create: [-2]


Qui deve tornare DBF esistente (invece torna Valore di uno dei campi non valido: nome, tipo o lunghezza). Io l'ho modificato nel senso che ho aggiunto il controllo per vedere se esiste il file. E infatti adesso funziona, solo che da quel test in poi mi ritorna sempre DBF esistente.

Manugal
29-03-2006, 19.37.27
Poi scusa un'altra cosa. Come faccio a scrivere tutta quella struttura che ho riempito tramite la fwrite? Come ho scritto io mi sa che non va bene.

quipo.it
29-03-2006, 20.17.27
no, non puoi scrivere una struttura su file... devi serializzarla in qualche modo in una stringa. Qual è il formato del file?

Manugal
29-03-2006, 21.10.20
Nelle specifiche c'è scritto di serializzare tutti i campi in un buffer e poi scriverli tutti d'un colpo sul file. Il formato del file non te lo so dire ma come puoi notare viene aperto in binario. Come posso fare allora?

quipo.it
29-03-2006, 21.14.10
qualcosa tipo

sprintf(buf, "%s|%d|%s|%s", h->stringval, h->intval, h->newstring, h->otherstring);

però bisognerebbe sapere quale formato usare...

quipo.it
29-03-2006, 21.19.22
BTW:

file LPC_CreateDBF.c

perché assegni due volte i valori ai campi della struttura (linee 49 e seguenti)

h->NumCampi = (uint16_t) htons(h->NumCampi); //inutile?

h->NumCampi = NumFields;
....


poi credo che i controlli all'interno dell'if() di riga 76 debbano essere messi in AND, non in OR:


strcpy(h->campo[i].name,FieldData[i].Name);

if ( (FieldData[i].FieldType != CHARACTER)
&& (FieldData[i].FieldType != NUMERIC)
&& (FieldData[i].FieldType != DATE)
&& (FieldData[i].FieldType != LOGICAL)
) {

Manugal
29-03-2006, 21.47.29
sprintf(buf, "%s|%d|%s|%s", h->stringval, h->intval, h->newstring, h->otherstring);

Non va bene perché sto scrivendo su file binari e quindi devo usare la fwrite().


h->NumCampi = (uint16_t) htons(h->NumCampi); //inutile?
h->NumCampi = NumFields;

Quello serve solamente per convertire il valore del campo in Network Byte Order (per la portabilità del codice). Altrimenti andrebbe solo su macchine Little Endian.


if ( (FieldData[i].FieldType != CHARACTER)
&& (FieldData[i].FieldType != NUMERIC)
&& (FieldData[i].FieldType != DATE)
&& (FieldData[i].FieldType != LOGICAL)
) {

Mi sa che hai ragione tu :D

quipo.it
29-03-2006, 21.52.27
Originariamente inviato da Manugal

sprintf(buf, "%s|%d|%s|%s", h->stringval, h->intval, h->newstring, h->otherstring);

Non va bene perché sto scrivendo su file binari e quindi devo usare la fwrite().


and? Prima serializzi la struttura in una stringa "buf", poi fai il dump del buffer su file con la fwrite()...

Originariamente inviato da Manugal

h->NumCampi = (uint16_t) htons(h->NumCampi); //inutile?
h->NumCampi = NumFields;

Quello serve solamente per convertire il valore del campo in Network Byte Order (per la portabilità del codice). Altrimenti andrebbe solo su macchine Little Endian.


d'accordo, ma se alla riga successiva lo sovrascrivi con un altro valore (NumFields), a che serve?

Manugal
29-03-2006, 21.56.57
and? Prima serializzi la struttura in una stringa "buf", poi fai il dump del buffer su file con la fwrite()...


Ok che ti serve sapere il formato di ogni campo della struct? La struct è definita nel file LPC_M1_Include.h che sta nella cartella /Modulo1/Include


d'accordo, ma se alla riga successiva lo sovrascrivi con un altro valore (NumFields), a che serve?


Quindi semmai dovrei fare l'operazione inversa, no?

quipo.it
29-03-2006, 22.05.53
Originariamente inviato da Manugal

and? Prima serializzi la struttura in una stringa "buf", poi fai il dump del buffer su file con la fwrite()...


Ok che ti serve sapere il formato di ogni campo della struct? La struct è definita nel file LPC_M1_Include.h che sta nella cartella /Modulo1/Include


beh, ti ho indicato come puoi procedere, ora divertiti un pochino tu... :D


Originariamente inviato da Manugal

d'accordo, ma se alla riga successiva lo sovrascrivi con un altro valore (NumFields), a che serve?


Quindi semmai dovrei fare l'operazione inversa, no?

già ;)

Manugal
29-03-2006, 22.07.33
Ma buf di che tipo deve essere? Cioè la struct dalla quale deve prendere i dati ha vari formati (int, short, long e anche un'altra struct al suo interno). Come faccio a passarglieli?

quipo.it
29-03-2006, 22.14.34
buf è una stringa definita come

char *buf;

fai una malloc della dimensione (in char) almeno pari alla dimensione della struttura, e poi serializzi i vari membri della struttura con una sprintf() come ti ho fatto vedere prima, mettendo un %s per i tipi stringa, un %d per i tipi intero, etc, con un separatore a scelta tra i vari campi. In questo modo puoi fare l'operazione inversa di estrazione in fase di lettura con una scanf() avente lo stesso formato.

Però, se da qualche parte hai le specifiche del formato del file, usa quelle...

Manugal
29-03-2006, 22.20.54
OK grazie proverò ;)

Manugal
30-03-2006, 15.58.08
Allora due punti mi sono un po' oscuri:

1 - Se ho un buffer di char e scrivo tramite la sprintf su questo buffer in realtà sto scrivendo delle stringhe (anche se ci metto dei numeri) e così non può andare se poi devo andarli a riversare su file.

2 - L'header è definito in questo modo:


typedef struct{
char name[DBF_NAME_LENGTH+1];
short NumCampi;
long NumRecords;
short dimHeader;
short dimRecord;
long timestamp;
campi campo[MAX_NUM_FIELDS];
}header;


Come vedi all'interno della struttura c'è un'altra struttura definita come campi. Questa come la passo al buffer?

Grazie.

quipo.it
30-03-2006, 16.46.37
Originariamente inviato da Manugal
1 - Se ho un buffer di char e scrivo tramite la sprintf su questo buffer in realtà sto scrivendo delle stringhe (anche se ci metto dei numeri) e così non può andare se poi devo andarli a riversare su file.


why not?

Originariamente inviato da Manugal
2 - L'header è definito in questo modo:


typedef struct{
char name[DBF_NAME_LENGTH+1];
short NumCampi;
long NumRecords;
short dimHeader;
short dimRecord;
long timestamp;
campi campo[MAX_NUM_FIELDS];
}header;


Come vedi all'interno della struttura c'è un'altra struttura definita come campi. Questa come la passo al buffer?

allo stesso modo, ricorsivamente... serializzi prima l'array, in un secondo momento serializzi gli altri campi + l'array h->campo serializzato in precedenza.

però forse ti conviene fare una funzione
char *serializeHeader(header h*) {}
che fa il tutto...

Non dico che sia l'unico metodo né il migliore, ma è forse il più pratico se devi poi leggere il file.

Manugal
30-03-2006, 16.51.22
why not?


Sinceramente non lo so... :D Vedendo il formato del buffer che è char allora ho pensato che forse non potesse andare bene.


allo stesso modo, ricorsivamente... serializzi prima l'array, in un secondo momento serializzi gli altri campi + l'array h->campo serializzato in precedenza.


Ok, ma posso fare tutto questo anche in un solo buffer?

quipo.it
30-03-2006, 16.56.49
Originariamente inviato da Manugal
Ok, ma posso fare questo anche in un solo buffer?

un buffer (tmp) temporaneo per contenere l'array h->campi[] serializzato, e uno (buf) per contenere gli altri campi+l'array serializzato prima. Una volta che hai serializzato tutto in buf, puoi liberare la memoria occupata da tmp e ritornare buf. BTW, ti conviene usare due separatori diversi per i due buffer...

Manugal
30-03-2006, 17.02.19
Secondo le specifiche c'è un NULL che separa ogni campo (che sarebbe h->campo) mentre gli altri campi non sono separati. Infine, alla fine dell'header, ci sono 2 NULL. Come faccio a inserire questi NULL?

Manugal
30-03-2006, 17.25.36
Ecco l'ho scritta. Però mi va in Segmentation Fault il penultimo test:


char *serializeHeader(header *h, int NumFields){
int i;
char *buffer,*tmp;
buffer=(char *)malloc(sizeof(h)*NumFields);
tmp=(char *)malloc(sizeof(campi));
for(i=0; i< NumFields; ++i)
sprintf(tmp,"%s%d%d%d", h->campo[i].name,h->campo[i].fieldtype,h->campo[i].fieldlen,NULL);
sprintf(buffer,"%s%d%d%d%d%d%s%d%d", h->name, h->NumCampi, h->NumRecords, h->dimHeader, h->dimRecord, h->timestamp, tmp, NULL, NULL);
free(tmp);
return buffer;
}

Manugal
30-03-2006, 17.29.49
Corretta!!! Però al test della correttezza dell'algoritmo mi dà sempre 0 punti:


char *serializeHeader(header *h, int NumFields){
int i;
char *buffer,*tmp;
buffer=(char *)malloc(sizeof(h)+2);
tmp=(char *)malloc(sizeof(campi)*NumFields+NumFields);
for(i=0; i< NumFields; ++i)
sprintf(tmp,"%s%d%d%d", h->campo[i].name,h->campo[i].fieldtype,h->campo[i].fieldlen,NULL);
sprintf(buffer,"%s%d%d%d%d%d%s%d%d", h->name, h->NumCampi, h->NumRecords, h->dimHeader, h->dimRecord, h->timestamp, tmp, NULL, NULL);
return buffer;
}


Forse è perché ho scritto male la fwrite?


int ret=fwrite(buf,sizeof(buf),1,fp);

quipo.it
30-03-2006, 17.31.28
forse qualcosa del genere?


tmp = (char *)malloc(sizeof(campi) * numcampi);
for(i=0; i< NumFields; ++i) {
sprintf(tmp, "%s%d%d%d", h->campo[i].name, h->campo[i].fieldtype, h->campo[i].fieldlen, NULL);
}
buffer = (char *)malloc(sizeof(h) * NumFields + strlen(tmp));
sprintf(buffer, "%s%d%d%d%d%d%s%d%d", h->name, h->NumCampi, h->NumRecords, h->dimHeader, h->dimRecord, h->timestamp, tmp, NULL, NULL);
free(tmp);
return buffer;

quipo.it
30-03-2006, 17.41.30
prova con strlen(buf) al posto di sizeof(buf)

poi hai invertito il secondo e terzo parametro:

int ret = fwrite(buf, sizeof(char), strlen(buf), fp);

Manugal
30-03-2006, 17.54.24
Come metto la free(tmp) mi appare questo:

*** glibc detected *** corrupted double-linked list: 0x08054638 ***

Se non la metto tutto ok. Però mi dà sempre 0 come punteggio. Ti posto il test che esegue: (mi manca solo questa cosa e poi ho finito tutto :) )


for(;;)
{
ret = -1;

fp = fopen("ProvaTest.dbf", "r");
len = fread(buftest, sizeof(char), 500, fp);
fclose(fp);

fp = fopen("Prova.dbf", "r");
len1 = fread(buf, sizeof(char), 500, fp);
fclose(fp);
if (len1 != len)
break;

// Confronto la prima parte (prima del timestamp)
len = DBF_NAME_LENGTH+1+2+4+2+2;
if (memcmp(buf, buftest, len))
break;

// Confronto la seconda parte (dopo il timestamp)
if (memcmp(buf+len+4, buftest+len+4, len1-len-4))
break;

ret = LPC_OK;
break;
}
if (ret == LPC_OK)
test[numtest].passed = 1;
numtest++;

quipo.it
30-03-2006, 17.56.16
mi mandi i files aggiornati?

Manugal
30-03-2006, 18.01.08
Ok. Eccoli

http://rapidshare.de/files/16798532/dbf.tar.gz.html

quipo.it
30-03-2006, 19.02.29
senti, mi sono accorto che c'è un RTF con le specifiche del progetto.
Lì è spiegato il formato del file.

Capitolo "Creazione e cancellazione di un DBF", paragrafo "Header del DBF".

Quindi, VISTO CHE TI VIENE DETTO COME CREARE IL FILE, rispetta le specifiche ;)

Lascia stare la serializzazione (tra l'altro, non ti eri accorto che continuavi a sovrascrivere in un for la variabile tmp, così che alla fine vi era contenuto solo l'ultimo record?).

Inoltre io direi di cambiare

h->NumCampi=NumFields;
h->NumCampi=(uint16_t) htons(h->NumCampi);

in qualcosa di più logico tipo:

h->NumCampi=(uint16_t) htons(NumFields);

(per tutti i campi della struttura)

;)

quipo.it
30-03-2006, 19.03.42
...

Manugal
30-03-2006, 19.07.44
Ok, non so davvero come ringraziarti. Ora vedo quello che posso fare, altrimenti lo consegno così (tanto ho superato tutti i test tranne questo :) ).

Manugal
30-03-2006, 19.13.27
...

quipo.it
30-03-2006, 19.17.22
Originariamente inviato da Manugal
Ok, non so davvero come ringraziarti. Ora vedo quello che posso fare, altrimenti lo consegno così (tanto ho superato tutti i test tranne questo :))

beh, è il test più importante... quello che verifica che il formato è corretto! Cmq è una cavolata, vedrai...