[C++] delete [] geeft segfault

Pagina: 1
Acties:

  • phaas
  • Registratie: Augustus 2001
  • Laatst online: 23-01-2025
In een class gebruik ik new[] en delete[] om een char* de (de)allocaten.
Deze char* moet rauwe data bevatten, dus ik kan geen string iod gebruiken omdat die de array afkappen bij een \0
Nu dacht ik zelf dat mijn mechaniek aardig werkte, maar op een één of andere manier segfault 'ie altijd in de destructor bij een delete[]....

Header:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 class E_EXPORT NetPacket
 {
   public:
   NetPacket();
   NetPacket(int code, QString argument ="");
   NetPacket(int code, char *data, int size = -1);
   NetPacket(QString string, bool b =true);
   NetPacket(char *data, bool b =true, int size = -1);
   ~NetPacket();

   QString argument();
   int code();
   char *argumentData();
   const char*argumentDataConst() const;
   int argumentLength();

   void setArgument(QString);
   void setArgument(const char *data, int size = -1);
   void setCode(int);

   void set(char *data, bool removeTrailingNewline = true, int size = -1);
   void set(QString, bool removeTrailingNewline = true);

   QString toString(bool addTrailingNewline = false);
   NetPacket&operator =(const NetPacket&);

   operator QString() { return toString(); }

   bool checkAnswer(int ok_code =0);

   // debug
   void print();

   private:
   int m_datasize;

   char *m_data;
   int m_code;
 };


Source (alleen boeiende dingen)
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
NetPacket::NetPacket()
   {
     m_data = 0;
     m_datasize = 0;
   }

   NetPacket::NetPacket(int c, QString arg)
   {
    m_code = c;
    m_data = 0;
    m_datasize =0;
    setArgument(arg);
   }

  NetPacket::NetPacket(int code, char *data, int size)
  {
     m_code = code;
     m_data = 0;
     m_datasize = 0;
     setArgument(data, size);
  }


  NetPacket::NetPacket(QString string, bool b)
  {
    m_data = 0;
    m_datasize = 0;
    set(string, b);
  }

  NetPacket::NetPacket(char *data, bool b, int size)
  {
    m_data = 0;
    m_datasize = 0;
    set(data, b, size);
  }

  NetPacket::~NetPacket()
  {
    /// Hier gaat het dus altijd fout, niet bij de andere delete[]'s
    if(m_data && m_datasize)
      delete [] m_data;
  }

  QString NetPacket::argument()
  {
    if(m_datasize == 0)
      return "";
    QString s;
    s.setAscii(m_data, m_datasize);
    return s;
  }

  void NetPacket::setArgument(QString s)
  {
    if(m_data)
    {
      delete [] m_data;
      m_data =0;
    }

    if(s.isEmpty())
    {
      m_data = 0;
      m_datasize = 0;
      return;
    }

    m_data = new char[s.length()+1];
    memcpy(m_data, s.data(), s.length()+1);
    m_datasize = s.length();
  }

  void NetPacket::setArgument(const char *data, int size)
  {
    if(m_data)
    {
      delete [] m_data;
      m_data =0;
      m_datasize =0;
    }

    if(size < 0)
    {
      QString s(data);
      if(s.isEmpty())
        return;
      m_data = new char[s.length()+1];
      memcpy(m_data, s.data(), s.length()+1);
      m_datasize = s.length();
    }
    else
    {
      if(size ==0)
        return;
      m_data = new char[size+1];
      memcpy(m_data, data, size);
      m_data[size] = '\0';
      m_datasize = size;
    }
  }

  void NetPacket::setCode(int i)
  {
    m_code = i;
  }

  void NetPacket::print()
  {
    cout << "'" << QString::number(m_code) << "' '" << m_data << "'" << endl;
  }


  void NetPacket::set(char *data, bool removeTrailingNewline, int size)
  {
    if(size < 0)
    {
      QString s(data);
      size = s.length();
    }

    if(size == 0)
      return;

    QString code;
    int offset, fromend =0;
    code.setAscii(data, 3);
    m_code = code.toInt();
    if(m_code < 100)
      offset = 0;
    else
      offset = 3;

    if(removeTrailingNewline)
    {
      if(data[size-1] == '\n')
        fromend = 1;
      if(data[size-1-fromend] == '\r')
        fromend++;
    }

    if(size-offset-fromend > 0)
      setArgument(data+offset, size-offset-fromend);

  }

  void NetPacket::set(QString c, bool removeTrailingNewline)
  {
    m_code = c.left(3).toInt();

    if(m_code < 100)
    {
      setArgument(c);
      m_code = 0;
      return;
    }

    QString argument;

    argument = c.right(c.length() - 3);

    if(removeTrailingNewline)
    {
    if(argument.at(argument.length()-1) == '\n')
      argument = argument.left(argument.length()-1);
    if(argument.at(argument.length()-1) == '\r')
      argument = argument.left(argument.length()-1);

    }
    setArgument(argument);
  }

  NetPacket& NetPacket::operator =(const NetPacket& p)
  {
    m_code = p.m_code;
    
    if(p.argumentDataConst() && p.m_datasize)
      setArgument(p.argumentDataConst(), p.m_datasize);
    
    return *this;
  }


Behoorlijk vaag als je het mij vraagt, maar misschien heb ik wat over het hoofd gezien.
Ik vind die hele delete[] zoiezo vaag: hoe weet die 'ie nou hoe groot je *array op dat moment is?

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Dit is wmb veel te veel code om door te gaan lezen, maar handige tip is dat delete [] enkel geneigd is segfaults te geven op 2 manieren:
• Dubbele free. Daar je na iedere delete[] de pointer op NULL zet onwaarschijnlijk, of je zou de destructor 2 keer aan moeten roepen. Dit *KAN* echter wel degelijk, daar je geen copy-constructor of operator= overloads hebt, en je dus per ongeluk een bitwise copy kunt uitlokken waardoor hetzelfde blok geheugen 2 keer gedelete wordt.
• Buffer over- of underruns. Als je buiten de block boundaries gaat zal delete soms segfaulten omdat de memory manager z'n data corrupted is.
Ik vind die hele delete[] zoiezo vaag: hoe weet die 'ie nou hoe groot je *array op dat moment is?
Dat weet de memory manager wel, zal ff quote opzoeken voor je over het nut van delete [].

Deze dus: [rml]curry684 in "[ C++] Classes new()bee probleem"[/rml]

Bouw in de tussentijd ff een copyconstructor en operator= :)

[ Voor 5% gewijzigd door curry684 op 25-03-2004 11:54 ]

Professionele website nodig?


  • phaas
  • Registratie: Augustus 2001
  • Laatst online: 23-01-2025
Hmmz, nu ik een copy-constructor heb toegevoegd kom ik al een heeel eind verder.
Hij segfault nu op een andere (veel latere) plek ;-)
GDB laat zien dat het toch nog om hetzelfde probleem gaat:
code:
1
2
3
4
5
6
7
8
9
10
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 16384 (LWP 10288)]
__libc_free (mem=0x4119f008) at malloc.c:3326
3326    malloc.c: No such file or directory.  <-- vaag?
        in malloc.c
(gdb) backtrace
#0  __libc_free (mem=0x4119f008) at malloc.c:3326
#1  0x40988de3 in operator delete(void*) (ptr=0x4119f000) at del_op.cc:39
#2  0x40988e3f in operator delete[](void*) (ptr=0x4119f000) at del_opv.cc:36
#3  0x400bd22e in ~NetPacket (this=0xbfffde10) at netpacket.cpp:78


Ik ga nog ff dat topic lezen...

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

phaas schreef op 25 maart 2004 @ 12:18:
Hmmz, nu ik een copy-constructor heb toegevoegd kom ik al een heeel eind verder.
Hij segfault nu op een andere (veel latere) plek ;-)
Hoe heb je de copy-constructor geschreven?

Want hiermee wordt het schrikwekkend duidelijk dat je dus ergens per ongeluk het ding kopieert, waarschijnlijk door 'm by-value te passen ergens. Zet eens een breakpoint in de copy-constructor (en vergeet de operator= niet).

Professionele website nodig?


  • phaas
  • Registratie: Augustus 2001
  • Laatst online: 23-01-2025
Ik ga vanmiddag even kijken, verder snap ik nog niet helemaal wat je bedoelt....
BTW, hoe plaats ik een breakpoint in GDB ^^ ?

Dit zijn de operator= en de copycon
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
NetPacket& NetPacket::operator =(const NetPacket& p)
  {
    m_code = p.m_code;
    
    if(p.argumentDataConst() && p.m_datasize)
      setArgument(p.argumentDataConst(), p.m_datasize);
    
    return *this;
  }

NetPacket::NetPacket(const NetPacket &p)
  {
    m_data = 0;
    m_datasize = 0;
    m_code = p.m_code;

    if(p.argumentDataConst() && p.m_datasize)
      setArgument(p.argumentDataConst(), p.m_datasize);
  }


de setArgument(char*, size) functie maakt een diepe kopie dmv. memcpy()

[ Voor 70% gewijzigd door phaas op 25-03-2004 12:58 ]


Verwijderd

hoe krijg je die cijfers en dat witte om je code heen net als dreamweaver?

modbreak
Met [code]-tags, zie de FAQ. Verder graag alleen on-topic opmerkingen aub :)

[ Voor 58% gewijzigd door curry684 op 25-03-2004 13:01 ]


  • MSalters
  • Registratie: Juni 2001
  • Laatst online: 09-04 22:08
Misschien dat je probleem 'm zit in QString::data()
const char * QString::data () const
This function is obsolete. It is provided to keep old source working. We strongly advise against using it in new code.
QString is slecht geschikt voor het opslaan en verwerken van binaire data, omdat elke char naar een QChar moet worden geconverteerd, en dat is een Unicode character.

Overigens kapt std::string helemaal niets af bij \0. Toegegeven, voor binaire data is std::string wat verwarrend, maar dus niet ongeschikt. Toch zou ik std::vector<unsigned char> willen aanraden, omdat die class binaire data suggereert.

Man hopes. Genius creates. Ralph Waldo Emerson
Never worry about theory as long as the machinery does what it's supposed to do. R. A. Heinlein


  • phaas
  • Registratie: Augustus 2001
  • Laatst online: 23-01-2025
Ik gebruik ook geen QString voor binairy data, daarvoor gebruik ik char ptrs.
Deze 'NetPacket' class bevat de rauwe data zoals die van het netwerk komt, of naar het netwerk toe gaat.
Als een gebruikersclass een netpacket object gebruikt kan gekozen worden om de rawdata, een size waarde en een code waarde te gebruiken of een conversie naar QString te laten doen door NetPacket.
QString gebruik ik voor regels uit tekstbestanden, configuratie bestanden, fout(meldingen) van de server.
Als ik 'rauw' bestanden overstuur, gebruik ik de char* uit netpacket ( argumentData() ).
Alles is intern ook geregeld met char*'s en de eerste conversie naar QString vind dan ook pas plaats in NetPacket.
Zo gaat het prima om bv. een wave-bestand van ong. 40mb over te sturen, dat gaat ook behoorlijk snel.
Ik heb het al met meer dingen geprobeerd en de md5sums kloppen altijd.
Het probleem met char* is idd, dat niet elke implentatie char als unsigned int8 heeft....
Nu kan ik hier toch weinig aan doen aangezien de socket-implentatie van Qt bij readBlock() met een char* werkt.
Mijn enige targets zijn op het moment GCC en MSVC++ en deze hebben naar mijn weten gewoon uint8 == char

BTW: QString::data() moet idd worden vervangen door QString::ascii()

BTW2:
Nu ik ook een operator=(const QString&) en NetPacket(const QString&) implv. NetPacket(QString) heb toegevoegd werkt het perfect :D

[ Voor 8% gewijzigd door phaas op 25-03-2004 17:02 ]


  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

Misschien nog even wat inhoudelijke opmerkingen: waarom heb je het nu in je laatste post wel over const QString & en doe je verder overal in je code by-value parameter passing? Ik zou daar ook een const-ref van maken :) Tevens snap ik niet waarom je 'operator QString' overload geen const-functie is, evenals ToString...

En je vergeet op een aantal plaatsen de parameternaam na het type in je header, dat is very bad practice ;) Echte code documenteert zichzelf, en dat doe je door in de naam aan te geven waar de parameter voor dient.

Professionele website nodig?


  • phaas
  • Registratie: Augustus 2001
  • Laatst online: 23-01-2025
Yep, hij ziet er nu zo uit:
code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
 class E_EXPORT NetPacket
 {
   public:
   NetPacket(); // Initialize with zero
   NetPacket(int code, const QString& argument =""); // deep-copy from QStringData
   NetPacket(int code, char *data, int size = -1); // deep-copy from raw
   NetPacket(const QString &string, bool removeTrailingNewline); // deep-copy from QStringData
   NetPacket(const QString &string);// deep-copy from QStringData
   NetPacket(char *data, bool b =true, int size = -1); // deep-copy from raw
   NetPacket(const NetPacket&); // deep-copy from NetPacket::m_data
   ~NetPacket();

   QString argument() const;
   int code() const;
   char *argumentData();
   const char*argumentDataConst() const;
   int argumentLength() const;

   void setArgument(const QString&);
   void setArgument(const char *data, int size = -1);
   void setCode(int);

   void set(char *data, bool removeTrailingNewline = true, int size = -1);
   void set(const QString&, bool removeTrailingNewline = true);

   QString toString(bool addTrailingNewline = false) const;
   NetPacket&operator =(const NetPacket&);
   NetPacket&operator =(const QString&);

   operator QString() const { return toString(); }

   bool checkAnswer(int ok_code =0) const;

   // debug
   void print() const;

   private:
   int m_datasize;

   char *m_data;
   int m_code;
 };


Netjes toch?
Een verder vind ik het toch altijd wel handig om de code een beetje duidelijker te maken met parameternamen.
Niet allemaal natuurlijk, maar niet alles ligt voor de hand.

  • curry684
  • Registratie: Juni 2000
  • Laatst online: 12-05 22:23

curry684

left part of the evil twins

d:)b
Een verder vind ik het toch altijd wel handig om de code een beetje duidelijker te maken met parameternamen.
Niet allemaal natuurlijk, maar niet alles ligt voor de hand.
Ik bedoelde juist dat het een goede gewoonte is om ze allemaal te doen, ook degenen die voor de hand liggen ;) Dat bedoel ik met 'goede code documenteert zichzelf' :P

Professionele website nodig?


  • phaas
  • Registratie: Augustus 2001
  • Laatst online: 23-01-2025
8)7 :z toch maar weer beter lezen volgende keer ;-)
Bedankt voor je hulp iig!
Pagina: 1