Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 476
  • Last Modified:

Stack overflow when calling outside a button routine

I am a C programmer trying to add some C-style code to an MFC generated button-on routine.  I need to copy some files from the button rouine so I've written a copy subroutine that I call several times from the button routine.  When I make the call, though, I immediately  get a stack overflow error. I wasn't sure where to put the copy routine so I just stuck it at the bottom of the file and then put a C-style delaration at the top of the file so my button routine could link to it. So basically I have,

UINT copy (char* source, char* destination);

{
    // button routine
    .
    .
    copy(source,destination);
}

UINT copy source, destination)
{
   // copy code
}

This could be something very stupid since this is the first MFC, or even C++ program for me, though I was encouraged when it compiled ok.

Thanks for any help.

Stevea

0
steva
Asked:
steva
  • 4
  • 3
  • 3
2 Solutions
 
AndyAinscowCommented:
This code looks like

MyFunc()
{
  MyFunc();
}

- It keeps calling itself endlessly hence your blown stack.
0
 
RuskialtCommented:
Like Andy states, this looks like a call to self. Stack overflows are usually caused by recursive calls to self. In this case all you need to do is rename one of the functions. Usually in MCF button functions are named like "OnSomething()" with an "On" prefix, indicating that some event occoured.
0
 
stevaAuthor Commented:
I don't see the call-to-self you guys are talking about.  The button routine calls copy() and then copy() does some work - which does not include calling itself.  Plus, I imagine that a call-to-self error would only overflow the stack after some large number of calls.  I get this error single-stepping through the code, as soon as my button routine executes the first call to copy().  Instead of control transferring to copy() I get an unhandled exception with an error number that maps to stack overflow.

Steve
0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
RuskialtCommented:
Could you copy/paste the most important lines of your code, so we can se te functions more clearly, I doubt your small example will compile. You'll see stack overflows even when singe stepping, if you singlestep over (and not into) a function that is self calling...
0
 
AndyAinscowCommented:
Ah - I see the first line was not associated with the code following it.
Post some real code.
0
 
stevaAuthor Commented:
I created a minimum program that still generates the error and named it StackOverflow. The code for the offending button routine is listed below.  I also found the line that makes it blow up, but I don't understand why. It's the line in copy() that declares buf.  If the size is 1048576 bytes (1MB) I get the error:

      Unhandled exception in StackOverflow.exe. 0xC00000FD: StackOverflow.

If I reduce the buf size to 1000000 with "CHAR buf[1000000] ;" everything works fine.  I'm compiling with Visual C++ 6.0.

Thanks for any ideas on what's going on,
Steve




// StackOverflowDlg.cpp : implementation file
//

#include "stdafx.h"
#include "StackOverflow.h"
#include "StackOverflowDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
      CAboutDlg();

// Dialog Data
      //{{AFX_DATA(CAboutDlg)
      enum { IDD = IDD_ABOUTBOX };
      //}}AFX_DATA

      // ClassWizard generated virtual function overrides
      //{{AFX_VIRTUAL(CAboutDlg)
      protected:
      virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
      //}}AFX_VIRTUAL

// Implementation
protected:
      //{{AFX_MSG(CAboutDlg)
      //}}AFX_MSG
      DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
      //{{AFX_DATA_INIT(CAboutDlg)
      //}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
      CDialog::DoDataExchange(pDX);
      //{{AFX_DATA_MAP(CAboutDlg)
      //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
      //{{AFX_MSG_MAP(CAboutDlg)
            // No message handlers
      //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CStackOverflowDlg dialog

CStackOverflowDlg::CStackOverflowDlg(CWnd* pParent /*=NULL*/)
      : CDialog(CStackOverflowDlg::IDD, pParent)
{
      //{{AFX_DATA_INIT(CStackOverflowDlg)
            // NOTE: the ClassWizard will add member initialization here
      //}}AFX_DATA_INIT
      // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
      m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CStackOverflowDlg::DoDataExchange(CDataExchange* pDX)
{
      CDialog::DoDataExchange(pDX);
      //{{AFX_DATA_MAP(CStackOverflowDlg)
            // NOTE: the ClassWizard will add DDX and DDV calls here
      //}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CStackOverflowDlg, CDialog)
      //{{AFX_MSG_MAP(CStackOverflowDlg)
      ON_WM_SYSCOMMAND()
      ON_WM_PAINT()
      ON_WM_QUERYDRAGICON()
      ON_BN_CLICKED(ID_DISABLE_ENABLE, OnDisableEnable)
      //}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CStackOverflowDlg message handlers

BOOL CStackOverflowDlg::OnInitDialog()
{
      CDialog::OnInitDialog();

      // Add "About..." menu item to system menu.

      // IDM_ABOUTBOX must be in the system command range.
      ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
      ASSERT(IDM_ABOUTBOX < 0xF000);

      CMenu* pSysMenu = GetSystemMenu(FALSE);
      if (pSysMenu != NULL)
      {
            CString strAboutMenu;
            strAboutMenu.LoadString(IDS_ABOUTBOX);
            if (!strAboutMenu.IsEmpty())
            {
                  pSysMenu->AppendMenu(MF_SEPARATOR);
                  pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
            }
      }

      // Set the icon for this dialog.  The framework does this automatically
      //  when the application's main window is not a dialog
      SetIcon(m_hIcon, TRUE);                  // Set big icon
      SetIcon(m_hIcon, FALSE);            // Set small icon
      
      // TODO: Add extra initialization here
      
      return TRUE;  // return TRUE  unless you set the focus to a control
}

void CStackOverflowDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
      if ((nID & 0xFFF0) == IDM_ABOUTBOX)
      {
            CAboutDlg dlgAbout;
            dlgAbout.DoModal();
      }
      else
      {
            CDialog::OnSysCommand(nID, lParam);
      }
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CStackOverflowDlg::OnPaint()
{
      if (IsIconic())
      {
            CPaintDC dc(this); // device context for painting

            SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

            // Center icon in client rectangle
            int cxIcon = GetSystemMetrics(SM_CXICON);
            int cyIcon = GetSystemMetrics(SM_CYICON);
            CRect rect;
            GetClientRect(&rect);
            int x = (rect.Width() - cxIcon + 1) / 2;
            int y = (rect.Height() - cyIcon + 1) / 2;

            // Draw the icon
            dc.DrawIcon(x, y, m_hIcon);
      }
      else
      {
            CDialog::OnPaint();
      }
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CStackOverflowDlg::OnQueryDragIcon()
{
      return (HCURSOR) m_hIcon;
}

//////// routine below added by me. Everything above generated by MFC - Steve
UINT
copy (CHAR * Source, CHAR * Destination)
{
      
      CString str;
      HANDLE srcHndl, destHandl;
      UCHAR buf[1048576];     // code works if this is [1000000] - Steve
      BOOL rd_status, wr_status;
      ULONG bytes_read, bytes_written;

            /*
                  Open source
            */

            srcHndl = CreateFile(Source,
                                           GENERIC_READ,
                                           FILE_SHARE_WRITE | FILE_SHARE_READ,
                                           NULL,
                                           OPEN_EXISTING,
                                           FILE_FLAG_NO_BUFFERING,
                                           NULL);
            
            return 1;

}

//////////// My modified button routine - Steve

void CStackOverflowDlg::OnDisableEnable()
{
      // TODO: Add your control notification handler code here

      CString strButton;

      GetDlgItem(ID_DISABLE_ENABLE)->GetWindowText(strButton);
      if (strButton.Compare("Disable") == 0)
            GetDlgItem(ID_DISABLE_ENABLE)->SetWindowText("Enable");
      else {
            GetDlgItem(ID_DISABLE_ENABLE)->SetWindowText("Disable");
            copy("c:\\meoff","c:\\meoff_bu");  // the bad call - Steve
      }

      
}
0
 
RuskialtCommented:
Declaring

UCHAR buf[1048576];

will put all those bytes on the stack, which is quite a large lump causing the stack overflow immmediately. The stack usually holds stuff like pointers to return address of subroutines and function parameters. Also holds classes or primitives instantiated inside function calls.

Try this instead

UCHAR* pBuffer = new UCHAR[0x100000];  //yes I love hex

to allocate on the heap. And don't forget to

delete pBuffer;

when you don't need the buffer anymore - at the of the function maybe..
0
 
AndyAinscowCommented:
project settings - Link tab, category output, field reserve in stack allocations.  Its probably empty in your app.  Put the cursor in there and press F1, you will get a help that says the default stack allocation is 1MB.  
Either assign a bigger stack or (assuming it is a buffer as you copy - and in that case the copy should be in a loop in case the file is larger than the buffer) use a smaller buffer.  Alternatively do as Ruskialt suggests and use new/delete to have it on the heap.

If it is copying I personally would use a smaller buffer (or the SHFileOperation function with FO_COPY to let the system copy it for you)
0
 
RuskialtCommented:
If you want to read a file into your buffer, why not allocate the actual size of the file, instead of assuming "There'll never be larger than 1MB file" - coz there will!
0
 
stevaAuthor Commented:
Thanks guys.  You were great!  I tried to increase the points and split them for you but the"Split" function limited me to the original 125.  I'll make it up next time. I just posted a question about assigning a bit-map to a dialog button that  I hope you guys will respond to.

Thanks again,
Steve
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

  • 4
  • 3
  • 3
Tackle projects and never again get stuck behind a technical roadblock.
Join Now