Solved

Stack overflow when calling outside a button routine

Posted on 2004-10-11
10
458 Views
Last Modified: 2013-11-20
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
Comment
Question by:steva
  • 4
  • 3
  • 3
10 Comments
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 12284198
This code looks like

MyFunc()
{
  MyFunc();
}

- It keeps calling itself endlessly hence your blown stack.
0
 
LVL 2

Expert Comment

by:Ruskialt
ID: 12286709
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
 

Author Comment

by:steva
ID: 12288992
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
 
LVL 2

Expert Comment

by:Ruskialt
ID: 12290752
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
 
LVL 44

Expert Comment

by:AndyAinscow
ID: 12291828
Ah - I see the first line was not associated with the code following it.
Post some real code.
0
Find Ransomware Secrets With All-Source Analysis

Ransomware has become a major concern for organizations; its prevalence has grown due to past successes achieved by threat actors. While each ransomware variant is different, we’ve seen some common tactics and trends used among the authors of the malware.

 

Author Comment

by:steva
ID: 12292555
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
 
LVL 2

Assisted Solution

by:Ruskialt
Ruskialt earned 62 total points
ID: 12295091
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
 
LVL 44

Accepted Solution

by:
AndyAinscow earned 63 total points
ID: 12295295
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
 
LVL 2

Expert Comment

by:Ruskialt
ID: 12295459
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
 

Author Comment

by:steva
ID: 12299116
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

Top 6 Sources for Identifying Threat Actor TTPs

Understanding your enemy is essential. These six sources will help you identify the most popular threat actor tactics, techniques, and procedures (TTPs).

Join & Write a Comment

Introduction: Dialogs (1) modal - maintaining the database. Continuing from the ninth article about sudoku.   You might have heard of modal and modeless dialogs.  Here with this Sudoku application will we use one of each type: a modal dialog …
Introduction: Dialogs (2) modeless dialog and a worker thread.  Handling data shared between threads.  Recursive functions. Continuing from the tenth article about sudoku.   Last article we worked with a modal dialog to help maintain informat…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now