Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Debug Assertion Failed / dbgheap.c / 1044

33 views
Skip to first unread message

Thorsten Albers

unread,
Mar 19, 2009, 2:08:09 PM3/19/09
to
Hi, Folks!

Unter VC++ 6.0/Windows XP SP2 habe ich folgendes Problem in dem angegebenen
Szenario:

- In einer DLL wird mit calloc() Speicher alloziert
- In einer EXE wird eine Funktion der DLL aufgerufen, über die dieser
Speicher (in einer Struktur) zurückgegeben wird

Der Speicher wird korrekt alloziert und kann in der EXE verwendet werden.
Wird der Speicher dann jedoch mit free() in der EXE freigegeben, kommt es
>nur in der Debug-Version< zu folgendem Fehler:

Debug Assertion Failed
...
File: dbgheap.c
Line: 1044
...
Expression: _CrtIsValidHeap(pUserData)
...

Die DLL wird mit "Multithreaded DLL debuggen", die EXE mit "Multithreaded
debuggen" kompiliert.

Schematisch(!) dargestellt mache ich folgendes:

----- DLL
Struktur.{LPCSTR}lpszFile = calloc(...)

----- EXE
{LPCSTR}lpszFile = Struktur.lpszFile
Struktur.lpszFile = NULL
...
free((LPSTR)lpszFile)

Hat jemand eine Idee, wo mein Fehler liegen könnte? Ich habe mich zwar
etwas in die unterschiedliche Verfahrensweise bei malloc() etc. in Release
und Debug eingelesen, aber Schlüsse auf meinen Fehler konnte ich nicht
ziehen. Google liefert viele Treffer, aber auch dort finde ich keinen
passender Hinweis.

Für Hilfe wäre wie immer dankbar,
Thorsten Albers

--
Thorsten Albers

albers (a) uni-freiburg.de

Stefan Kuhr

unread,
Mar 19, 2009, 3:21:32 PM3/19/09
to
Hallo Thorsten,

Thorsten Albers wrote:
> Hi, Folks!
> <snip>


> Hat jemand eine Idee, wo mein Fehler liegen könnte? Ich habe mich zwar
> etwas in die unterschiedliche Verfahrensweise bei malloc() etc. in Release
> und Debug eingelesen, aber Schlüsse auf meinen Fehler konnte ich nicht
> ziehen. Google liefert viele Treffer, aber auch dort finde ich keinen
> passender Hinweis.
>

Das ist der Suendenfall schlechthin, einen runtime-Allokator zu
verwenden und den Eigentuemer in Form der Module zu wechseln. Nimm einen
runtime-unabhaengigen Allokator wie etwa LocalAlloc und das Problem geht
vorbei.

--
S

Thorsten Albers

unread,
Mar 19, 2009, 7:01:22 PM3/19/09
to
Stefan Kuhr <kust...@gmx.li> schrieb im Beitrag
<ul0vsfMq...@TK2MSFTNGP03.phx.gbl>...

> Das ist der Suendenfall schlechthin, einen runtime-Allokator zu
> verwenden und den Eigentuemer in Form der Module zu wechseln. Nimm einen
> runtime-unabhaengigen Allokator wie etwa LocalAlloc und das Problem geht
> vorbei.

Aber das wäre ja extrem besch... Ich meine, die DLL und die EXE gehören zum
selben Prozess und verwenden denselben virtuellen Speicher, und trotzdem
sollte sich über malloc() allozierter Speicher nicht zwischen beiden
austauschen lassen? Und wo liegt der Unterschied zwischen malloc() und
LocalAlloc(), wenn beide Heap-Speicher allozieren?
Da ich in der Release-Version keinen Speicherverlust beobachten kann,
vermutete ich zuletzt, daß es an der besonderen Verwaltungsmethode des
Heap-Speichers im Debug-Modus liegen könnte. Aber selbst da fände ich es
unlogisch, da DLL und EXE dienselbe Speichverwaltung verwenden.

Na ja, ich werde 'mal Deinem Rat folgen und auf LocalAlloc() umstellen -
aber die Logik bei MS kann ich da nicht erkennen...

Thorsten Albers

unread,
Mar 19, 2009, 8:04:15 PM3/19/09
to
Thorsten Albers <alber...@THISuni-freiburg.de> schrieb im Beitrag
<eLQBgaOq...@TK2MSFTNGP03.phx.gbl>...

> Aber das wäre ja extrem besch... Ich meine, die DLL und die EXE gehören
zum
> selben Prozess und verwenden denselben virtuellen Speicher, und trotzdem
> sollte sich über malloc() allozierter Speicher nicht zwischen beiden
> austauschen lassen? Und wo liegt der Unterschied zwischen malloc() und
> LocalAlloc(), wenn beide Heap-Speicher allozieren?

O.k., mir ist jetzt klar, daß es mit der Speicherverwaltung von Windows NT
zusammenhängt. Bisher habe ich immer unter Windows 98 SE entwickelt und
dann die Release-Version unter Windows XP getestet - da trat der Fehler
dann natürlich nie auf....

Jochen Kalmbach [MVP]

unread,
Mar 20, 2009, 2:47:11 AM3/20/09
to
Hallo Thorsten!

> Aber das wäre ja extrem besch... Ich meine, die DLL und die EXE gehören zum
> selben Prozess und verwenden denselben virtuellen Speicher, und trotzdem
> sollte sich über malloc() allozierter Speicher nicht zwischen beiden
> austauschen lassen?

Du kannst das wu8nderbar machen, *solange* Du genau die selber CRT
verwendest!!! Also die "DLL-Version der gleichen CRT-Version"!
Dann gibt es keine Probleme.

Jede CRT verwendet Ihren eigenen Heap; deshalb gibt es Probleme, wenn Du
unterschiedliche CRTs verwendest (oder gar statisch linkst).

> Und wo liegt der Unterschied zwischen malloc() und
> LocalAlloc(), wenn beide Heap-Speicher allozieren?

malloc gehört zur CRT; somit musst Du die selbe CRT verwenden, wenn Du
malloc/free verwenden willst.

LocalAlloc gehört zur WinAPI. Somit musst Du die selbe WinAPI verwenden,
wenn Du dies benutzen willst (und die selbe WinAPI verwendest Du ja
schon implizit; somit ist dieser Fall einfacher ;) ).

> Da ich in der Release-Version keinen Speicherverlust beobachten kann,
> vermutete ich zuletzt, daß es an der besonderen Verwaltungsmethode des
> Heap-Speichers im Debug-Modus liegen könnte.

Mit Debug/Release hat das nix zu tun. Nur im Debug-Mode wird halt die
Fehlermeldung ausgegeben.

> Aber selbst da fände ich es
> unlogisch, da DLL und EXE dienselbe Speichverwaltung verwenden.

Wenn dies so wäre, dann hättest Du kein Problem.

> Na ja, ich werde 'mal Deinem Rat folgen und auf LocalAlloc() umstellen -
> aber die Logik bei MS kann ich da nicht erkennen...

Stelle Deine beiden Projekte auf die selbe DLL-CRT um, dann gibt es auch
keine Probleme.

--
Greetings
Jochen

My blog about Win32 and .NET
http://blog.kalmbachnet.de/

Jochen Kalmbach [MVP]

unread,
Mar 20, 2009, 2:50:29 AM3/20/09
to
Hallo Thorsten!

> Die DLL wird mit "Multithreaded DLL debuggen", die EXE mit "Multithreaded
> debuggen" kompiliert.

Somit verwendest Du *nicht* die selbe CRT und Dein Vorhaben muss
schiefgehen.
Stelle beides auf das gleiche "* DLL *" um.

Stefan Kuhr

unread,
Mar 20, 2009, 5:43:30 AM3/20/09
to
Hallo beisammen,

Jochen Kalmbach [MVP] wrote:
> <snip>


> Stelle Deine beiden Projekte auf die selbe DLL-CRT um, dann gibt es auch
> keine Probleme.
>

Es wird auch dann Probleme geben, wenn man diesen Ratschlag von Jochen
befolgt, aber die EXE von der DLL unabhaengig updated (oder umgekehrt)
und dabei fuer eine der Komponenten eine neuere oder aeltere
Compilerversion einsetzt. Daher halte ich es fuer sinnvoller, beim
"Besitzertausch" von Speicher zwischen Modulen immer
runtime-unabhaengige Allokatoren zu verwenden. Wenn Thorsten natuerlich
sicherstellen kann, dass er DLL und EXE immer paarweise ausliefert und
alles immer mit derselben Compilerversion und derselben runtime-Variante
gebuildet wurde, kann man auch runtime-basierte Allokatoren verwenden.

--
S


Alexander Sailer

unread,
Mar 20, 2009, 6:37:00 AM3/20/09
to
Hallo Stefan:

> Es wird auch dann Probleme geben, wenn man diesen Ratschlag von Jochen
> befolgt, aber die EXE von der DLL unabhaengig updated (oder umgekehrt)
> und dabei fuer eine der Komponenten eine neuere oder aeltere
> Compilerversion einsetzt. Daher halte ich es fuer sinnvoller, beim
> "Besitzertausch" von Speicher zwischen Modulen immer
> runtime-unabhaengige Allokatoren zu verwenden. Wenn Thorsten natuerlich
> sicherstellen kann, dass er DLL und EXE immer paarweise ausliefert und
> alles immer mit derselben Compilerversion und derselben runtime-Variante
> gebuildet wurde, kann man auch runtime-basierte Allokatoren verwenden.


Mir persönlich erscheitn es am Sinnvollsten, wenn der übergebene
Parameter bereits Speicher allokiert und nur befüllt wird. Somit kann er
problemlos nacher wierder befreit werden.


--
MfG Alex

SvenC

unread,
Mar 20, 2009, 7:23:29 AM3/20/09
to
Hi Alexander,

> Mir persönlich erscheitn es am Sinnvollsten, wenn der übergebene Parameter
> bereits Speicher allokiert und nur befüllt wird. Somit kann er problemlos
> nacher wierder befreit werden.

Und wenn Du die Größe gar nicht vorher weißt? Dann müsstest Du immer
einen Call zum Größenbestimmen vorwegschicken. Auch lästig, oder?

--
SvenC

Alexander Sailer

unread,
Mar 20, 2009, 8:24:07 AM3/20/09
to
Hallo SvenC:

> Und wenn Du die Größe gar nicht vorher weißt? Dann müsstest Du immer
> einen Call zum Größenbestimmen vorwegschicken. Auch lästig, oder?

Das ist wahr, aber auf jeden Fall sicherer als die Ursprungsvariante:)

--
Just my 0,02 €
Alex

Thorsten Albers

unread,
Mar 20, 2009, 8:27:07 AM3/20/09
to
Jochen Kalmbach [MVP] <nospam-Joch...@holzma.de> schrieb im Beitrag
<uZV3pgSq...@TK2MSFTNGP02.phx.gbl>...

> Somit verwendest Du *nicht* die selbe CRT und Dein Vorhaben muss
> schiefgehen.
> Stelle beides auf das gleiche "* DLL *" um.

Aha! Ich dachte nicht, daß in der Beziehung zwischen "Multithreaded DLL
debuggen" und "Multithreaded debuggen" noch ein Unterschied wäre.

Was mich aber wundert: Warum funktioniert das unter Windows 9x, unter
Windows NT aber nicht? Denn an einer unterschiedlichen Speicherverwaltung
des Betriebssystemes, wie ich zwischenzeitlich gedacht hatte, liegt es
offenbar ja nicht.

Kann man Vorteile und/oder Nachteile benennen, wenn ich auch die EXE auf
"Multithreaded DLL debuggen" umstelle?
Und kann man Vorteile und/oder Nachteile einer Umstellung auf LocalAlloc()
benennen?

Vielen Dank für alle Antworten hier im Thread an alle!

Jochen Kalmbach [MVP]

unread,
Mar 20, 2009, 8:33:43 AM3/20/09
to
Hallo Thorsten!

> Was mich aber wundert: Warum funktioniert das unter Windows 9x, unter
> Windows NT aber nicht?

Es funktioniert dort genausowenig. Vermutlich hast Du nur die
Release-Version getestet, welche den Fehler nicht meldet.

> Kann man Vorteile und/oder Nachteile benennen, wenn ich auch die EXE auf
> "Multithreaded DLL debuggen" umstelle?

Wenn Du eh schon ein Projekt mit "DLL" hast, dann hat es keine
Nachteile, sondern nur vorteile.

> Und kann man Vorteile und/oder Nachteile einer Umstellung auf LocalAlloc()
> benennen?

Aufwand?

Martin Richter [MVP]

unread,
Mar 20, 2009, 8:40:10 AM3/20/09
to
Hallo Alexander!

> Mir persönlich erscheitn es am Sinnvollsten, wenn der übergebene
> Parameter bereits Speicher allokiert und nur befüllt wird. Somit kann er
> problemlos nacher wierder befreit werden.

Ich halte die Verursacher Variante immer für am sinnvollsten:
Nur das Modul, das den Speicher allokiert hat darf ihn auch freigeben...

--
Martin Richter [MVP] WWJD http://blog.m-ri.de
"A well-written program is its own heaven; a poorly written
program is its own hell!" The Tao of Programming
FAQ: http://www.mpdvc.de Samples: http://www.codeproject.com

Alexander Sailer

unread,
Mar 20, 2009, 8:53:17 AM3/20/09
to
Hallo Martin Richter [MVP]:

> Ich halte die Verursacher Variante immer für am sinnvollsten:
> Nur das Modul, das den Speicher allokiert hat darf ihn auch freigeben...

Genau das sagte, ...äh schrieb, ich doch eben.

--
Alex

SvenC

unread,
Mar 20, 2009, 9:23:37 AM3/20/09
to
Hi Alex,

>> Ich halte die Verursacher Variante immer für am sinnvollsten:
>> Nur das Modul, das den Speicher allokiert hat darf ihn auch freigeben...
>
> Genau das sagte, ...äh schrieb, ich doch eben.

Nicht ganz. Martins Variante geht auch, wenn die dll selber ein
"Free"-Funktion anbietet. Dann kann sie Dir einen allozierten
Block rausreichen und zum Freigeben rufst Du die Free-Funktion
aus, die dann eben auch in der dll implementiert ist.

--
SvenC

Martin Richter [MVP]

unread,
Mar 20, 2009, 9:34:15 AM3/20/09
to
Hallo!

Jupp! Das erlaubt jede Art von Mischung und Freiheit... ;)

Ein schönes Wochenende allerseits...

Thorsten Albers

unread,
Mar 20, 2009, 10:28:05 AM3/20/09
to
Jochen Kalmbach [MVP] <nospam-Joch...@holzma.de> schrieb im Beitrag
<OMYUdgVq...@TK2MSFTNGP03.phx.gbl>...

> Es funktioniert dort genausowenig. Vermutlich hast Du nur die
> Release-Version getestet, welche den Fehler nicht meldet.

Nein. Dieselbe EXE/DLL-Kombination führt unter WinXP zum Fehler, unter
Win98SE nicht.

> Wenn Du eh schon ein Projekt mit "DLL" hast, dann hat es keine
> Nachteile, sondern nur vorteile.

> Aufwand?

Also nichts 'bewegendes'...

Stefan Kuhr

unread,
Mar 20, 2009, 12:34:17 PM3/20/09
to
Hi Alexander,

Na klar, da kann man geteilter Meinung sein. Ich wuerde aber niemandem
in sein Funktions- oder API-Design dreinreden wollen, wenn er's trotzdem
so macht. Ich finde es grundsaetzlich nicht verkehrt, wenn eine Funktion
allozierten Speicher zurueckgibt, denn das kann auch race conditions
vermeiden helfen: Ansonsten muss der Aufrufer eventuell erst ermitteln
wieviel Speicher er bereitstellen muss um ihn zu allozieren und der
Funktion zu uebergeben. Hat sich zwischenzeitlich der Speicherbedarf
fuer den Aufruf geaendert, muss die Funktion trotzdem scheitern. Das
altbekannte Paradigma im Win32-API, eine Funktion erst gezielt scheitern
zu lasssen um erforderliche Puffergroessen zu ermitteln, dann den
Speicher zu allozieren um schliesslich die Funktion mit einem Puffer der
richtigen Groesse aufzurufen geht eben nicht immer.


--
S

Alexander Sailer

unread,
Mar 23, 2009, 4:33:46 AM3/23/09
to
Hallo Stefan:

> Na klar, da kann man geteilter Meinung sein. Ich wuerde aber niemandem
> in sein Funktions- oder API-Design dreinreden wollen, wenn er's trotzdem
> so macht.

Dies war nie meine Absicht. Ich habe nur meine Meinung kundgetan. Ich
wollte in keinster Weise jmd. überreden dies nach dem Schema welches ich
benutze zu machen.
Wie gesagt: Nur ein Vorschlag!

--
MfG Alex

0 new messages