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

Stack Memory Leak in C#

83 views
Skip to first unread message

Robert Bouillon

unread,
Apr 26, 2005, 12:08:01 PM4/26/05
to
I've got a memory leak problem with my Stack in a class I created for Serial
Port Communication.

I've narrowed it doen to a subclass I created to monitor the Win32 events
fired for the Serial Port (Using WaitCommEvent).

The "Status" subclass allocates unmanaged memory for the Event Handle and
Overlapped struct in the ctor and frees the memory in the
(IDisposable).Dispose method for the object. An infinite loop checks the
event / status on a background thread. No memory is allocated explicitly in
this loop, however I'm definately leaking my stack memory from within this
loop.

This leads me to believe it's a problem with my P/Invoke declarations. The
only thing I do differently than most other P/Invoke statements I've seen is
rather than using "out uint" for event masks, I'm using "out MyEnum". I
think this is where my problem lies, however it takes me almost an hour to
reproduce this error so I'm having some difficulty narrowing it down.

<code>
[Flags]
private enum ModemStatus : uint
{
MS_CTS_ON = 0x0010,
MS_DSR_ON = 0x0020,
MS_RING_ON = 0x0040,
MS_RLSD_ON = 0x0080
}

[DllImport("kernel32.dll")]
private static extern bool GetCommModemStatus(IntPtr hFile, out
ModemStatus lpModemStat);
</code>

Do I have to clean lpModemStat explicitly?
Is this possibly a problem with P/Invoke?
How can I explicitly free lpModemStat for testing?
Is there a way for me to watch my stack allocation at runtime?

Thanks in Advance

(P.S. Sorry for the duplicate post. This was originally posted in
microsoft.public.dotnet.framework until I realized that it's likely an
interop issue)


Gabriel Lozano-Morán

unread,
Apr 26, 2005, 1:49:26 PM4/26/05
to
> [DllImport("kernel32.dll")]
> private static extern bool GetCommModemStatus(IntPtr hFile, out
> ModemStatus lpModemStat);

What happens if for example the CTS signal and ring indicator signal are
both on?

...
[DllImport("kernel32.dll")]
private static extern Boolean GetCommModemStatus(IntPtr hFile, out uint
lpModemStat);
...
if(GetCommModemStatus(handle, out modemStatus) == true)
{
bool MS_CTS = ((modemStatus & (uint)ModemStatus.MS_CTS_ON) != 0);
bool MS_DSR = ((modemStatus & (uint)ModemStatus.MS_DSR_ON) != 0);
bool MS_RING = ((modemStatus & (uint)ModemStatus.MS_RING_ON) != 0);
bool MS_RLSD = ((modemStatus & (uint)ModemStatus.MS_RLSD_ON) != 0);
}

Gabriel Lozano-Morán


Robert Bouillon

unread,
Apr 26, 2005, 3:00:31 PM4/26/05
to
The FLAGS attrbute allows the ToString to display all applicable flags as
they relate to the enumerated value:

==========================
[Command Window]
> lpModemStat.ToString()
> "MS_CTS_ON,MS_RING_ON"
==========================

The actual code method is:

==========================
public void UpdateLines()
{
ModemStatus ms;
while(!GetCommModemStatus(p_Parent.hPort,out ms))
if(Win32Exception.Check(false)==NativeError.ERROR_IO_PENDING)
continue;
else
throw new Win32Exception("Error during GetCommModemStatus");

if(((ms&ModemStatus.MS_CTS_ON)!=0)!=p_CTS)
p_CTS = !p_CTS;

if(((ms&ModemStatus.MS_DSR_ON)!=0)!=p_DSR)
p_DSR = !p_DSR;

if(((ms&ModemStatus.MS_RING_ON)!=0)!=p_Ring)
p_Ring = !p_Ring;

if(((ms&ModemStatus.MS_RLSD_ON)!=0)!=p_RLSD)
p_RLSD = !p_RLSD;
}
===========================

Object events are fired as a direct result of an EV_* flag in the calling
method. This method only serves to update line status.

I've found it to make my code a lot cleaner, as long as it's not the cause
of this Memory Leak.

Any ideas on what may be causing this?

--ROBERT


"Gabriel Lozano-Morán" <gabriel...@no-spam.com> wrote in message
news:Oeb4kgoS...@TK2MSFTNGP14.phx.gbl...

Gabriel Lozano-Morán

unread,
Apr 26, 2005, 3:18:44 PM4/26/05
to
I am just wondering what would open if an error occured in the
GetCommModemStatus function and the out parameter doesn't get set or what
value is given to the out parameter when an error occurs? Also have you
tried using a ref parameter instead?

Gabriel Lozano-Morán

"Robert Bouillon" <djwhi...@hotmail.com> wrote in message
news:u8kmMIpS...@tk2msftngp13.phx.gbl...

Robert Bouillon

unread,
Apr 26, 2005, 3:59:26 PM4/26/05
to
As far as I know, the value is set to 0 on error.

It's worth a shot. It's just difficult, as it takes me about an hour to
reproduce this error.

--ROBERT
"Gabriel Lozano-Morán" <gabriel...@no-spam.com> wrote in message

news:ebA%23eSpSF...@tk2msftngp13.phx.gbl...

Robert Bouillon

unread,
Apr 27, 2005, 8:24:06 AM4/27/05
to
The problem was actually a bad ReadFile / WriteFile P/Invoke declaration.

private static extern bool WriteFile(IntPtr fFile, Byte[] lpBuffer,
UInt32 nNumberOfBytesToWrite, out UInt32 lpNumberOfBytesWritten,
IntPtr lpOverlapped);


private static extern bool ReadFile(IntPtr hFile, [Out] Byte[] lpBuffer,
UInt32 nNumberOfBytesToRead,
out UInt32 nNumberOfBytesRead, IntPtr lpOverlapped);


was changed to:

static extern bool WriteFile(IntPtr hFile, byte [] lpBuffer,uint
nNumberOfBytesToWrite, out uint lpNumberOfBytesWritten,
[In] ref System.Threading.NativeOverlapped lpOverlapped);

public static extern bool ReadFile(IntPtr hFile, [Out] byte[] lpBuffer,
uint nNumberOfBytesToRead,
out uint lpNumberOfBytesRead, [In] ref
System.Threading.NativeOverlapped lpOverlapped);


Despite the fact that "Overlapped" is a struct, the P/Invoke prevented the
data from being freed when the variable fell out of scope.

Maybe this will help someone in the future. Thanks to everyone who posted.

--ROBERT


"Robert Bouillon" <djwhi...@hotmail.com> wrote in message

news:%23uPmGpp...@TK2MSFTNGP14.phx.gbl...

0 new messages