Solved

Program runs fine in Microsoft Visual C++ debugger, but crashes outside the debugger.

Posted on 2007-03-19
7
272 Views
Last Modified: 2008-01-09
I'm running the following program, which truncates any text string longer than 32000 characters to 32000 characters. When the number of text string "nchar" is about 90000,  here is what I observed:

1). When I run it through Microsoft Visual C++ debugger, it seems to work fine.

2). When I run it outside Microsoft Visual C++ debugger, it crashes at the following line of code:
pBuf = (InlineBuf *)fcalloc(1, sizeof(InlineBuf));

3). Since the observations 1) and 2) strongly suggests that there is a memory overflow, I did a Purify test, which reports the following two memory errors:
Error 1: ABW: Array bounds write  (2 times) -- Writing 22 bytes to 0x34b736 in the heap (13 bytes at 0x34b73f illegal)
Error 2: ABR: Array bounds read  (2 times) -- Reading 18 bytes from 0x34b73a in the heap (13 bytes at 0x34b73f illegal)
However, I noticed that the above two memory errors reported by Purify both occured before the line of code that crashes.

4). When the number of text string "nchar" is less than 32000, the program works fine.

5). When the number of text string "nchar" is about 40000, the program crashes at the same place, and Purify reports the nearly the same memory errors except that there are no "(2 times)" in the error messages.

Something to be done soon: while posting this question, I'm waiting for doing another Purify test, which is to run the program when nchar is less than 32000 to see if the two memory errors still occur. However, our Purify build of today is temporarily not ready, but I'll do the test as soon as it's ready and let you know the result.

Please advise on where the problem could be.

Thank you in advance for your help!


#define LIST_INFO(type)  type *next; \
    type *tail; \
    type *previous;

typedef struct inlineBuf_s
{
    LIST_INFO(struct inlineBuf_s)
    char line[SS_MAX_TEXT_LEN + 1];
}
InlineBuf;

#define SS_MAX_TEXT_LEN     32000

#define fcalloc calloc

/* sswsty(): called from ontab() when it sees "ON TABLE/GRAPH SET  */
/* STYLE/GRAPHSTYLE *", or from ssset() when it sees "SET STYLE=*" */
/* (PUTSTYLE). */
/* Copies the in-line stylesheet following the above, up to */
/* "ENDSTYLE" or "END", into a buffer in memory. */
/* 'inlineType' parameter is one of the IS_* constants in sshdr.h. */
 
long sswsty (t_cbh *cbh, long inlineType)
{
    t_stylcm  *  stylcm = (t_stylcm  *) cbh->cb[C_STYLCM];
    t_ptbcm   *   ptbcm = (t_ptbcm   *) cbh->cb[C_PTBCM];
    t_pipeds  *  pipeds = (t_pipeds  *) cbh->cb[C_PIPEDS];
    t_currnt  *  currnt = (t_currnt  *) cbh->cb[C_CURRNT];
    long rc = 0;
    InlineBuf *pBuf;
    InlineBuf *pLongBuf;
    BOOL_ truncated = FALSE;
    BOOL_ needTruncation = FALSE;
    BOOL_ previousLineEndedByDollarSignNaturally = TRUE;
    BOOL_ isNewStyleSheetStatement = FALSE;

    /* If FORECASTing, the style is parsed twice.  However,           */
    /* stylcm->inlineList is only freed (in cerrget() or if an error  */
    /* occurred in sstcl3()) the final time, resulting in Memory      */
    /* Leaks.  The same is true for stylcm->inlineGraph, which is     */
    /* only freed the final time in sstcl3().  Therefore, ensure that */
    /* inlineList and inlineGraph are freed before re-use.            */
    /*                                    - BSK: MIPS 98423 PNO 50823 */
    /* PUTSTYLE stylesheets are cumulative, and are only freed at */
    /* the end of a TABLE request (sstcl3()), so don't free: */
    if (inlineType != IS_PUTSTYLE)
        freeInlineStyle(cbh, inlineType);
 
    while (TRUE)
    {
        long nchar, retcod;
        long numLBlk = 0;
        char *pstyBuf = stylcm->styleLine;
 
        /* read from pooled tables stack */
        if (ptbcm->Head_stack) {
          long ne;
          ptbget(cbh, &nchar, stylcm->styleLine, &ne);
        }
        else {
          /* Take Behavior from NEXT FORTRAN else when REQCTL is call
             a second time because of AUTOINDEX, the pipe will not
             contain the inline style */
          if (pipeds->hasdat) {
              pipein(cbh, &nchar, stylcm->styleLine, &retcod);
              if(retcod) termin(&nchar, stylcm->styleLine, &retcod);
          }
          else {
              termin(&nchar, stylcm->styleLine, &retcod);
          }
          if (ptbcm->ptph == PTPHDY) {
            char hold_line[LINELIMEDA];
            long hold_ichar = currnt->ichar, c__0 = 0;
            currnt->ichar = nchar;
            memcpy(hold_line, currnt->line, (short)nchar);
            memcpy(currnt->line, stylcm->styleLine, (short)nchar);
            addsrc(cbh, &c__0);
            memcpy(currnt->line, hold_line, (short)nchar);
            currnt->ichar = hold_ichar;
          }
        }
 
        if ((pipeds->record==1)&&(&nchar!=0)&&(pipeds->recerr<1)) {
            chkpip ( cbh, stylcm->styleLine, &nchar, &retcod );
            if ( !retcod )
                rectok(cbh, stylcm->styleLine, &nchar);
            pipeds->recerr=0;
        }
        if (nchar <= 0) break;
 
        /* If 'ENDSTYLE' at beginning of line, we're done: */
        /* Count number of leading blanks */
        numLBlk = cvscnne(nchar, pstyBuf, ' ') - 1;
        if (numLBlk < 0) numLBlk = 0;
        /* Truncate leading blanks and get resulting number characters */
        pstyBuf += numLBlk;
        nchar = cvscnneb(nchar-numLBlk, pstyBuf, ' ');
        if ((nchar == 8) && (memcmp(pstyBuf, "ENDSTYLE", 8) == 0))
            break;
 
        /* If 'END', 'RUN' or 'QUIT', we're done: */
        endr(&rc, &nchar, pstyBuf);
        if (rc != 0) {
            if (pipeds->record == 1)     /* Recording TABLE request? */
            {
                long zero = 0;
                rectok(cbh, " ",&zero);
                pipeds->record=0;        /* Stop recording */
            }
 
            /* For FORECAST, it is essential that currnt->text */
            /* contain the word "END" if it was found (see code */
            /* in tabctl.c after call to reqctl()): */
            memcpy(currnt->text, stylcm->styleLine, 8);
 
            break;
        }

        if (ptbcm->ptph == PTPHDY)
            continue;

        if (truncated && !isNewStyleSheetStatement) {
            long equalSign = cvscneqb(nchar, stylcm->styleLine, '=');                    
            long closingQuote = cvscneqb(nchar, stylcm->styleLine, '\'');
            BOOL_ hasMoreKeywords = (equalSign - closingQuote) > 0;

            if (hasMoreKeywords) {
                long comma = cvscneq(nchar - closingQuote, stylcm->styleLine + closingQuote, ',');
                nchar -= closingQuote + comma;
                pstyBuf = stylcm->styleLine + closingQuote + comma;

                pLongBuf->line[SS_MAX_TEXT_LEN - 1] = ' ';
                truncated = FALSE;
            }
            else {
                previousLineEndedByDollarSignNaturally = (*(stylcm->styleLine + nchar -1) == '$') ? TRUE: FALSE;
                isNewStyleSheetStatement = previousLineEndedByDollarSignNaturally ? TRUE: FALSE;
                continue;
            }
        }
 
        /* 36575 restore a pstyBuf pointer and nchar for truncated
           leading blank */
        if (numLBlk > 0) {
           nchar += numLBlk;
           pstyBuf = stylcm->styleLine;
        }
 
        if (nchar > SS_MAX_TEXT_LEN) {
            nchar = SS_MAX_TEXT_LEN;
            truncated = TRUE;
            needTruncation = TRUE;
        }

        /* Allocate a new buffer for this line, and link it */
        /* into the appropriate list: */    
        pBuf = (InlineBuf *)fcalloc(1, sizeof(InlineBuf));
       
        memcpy(pBuf->line, pstyBuf, nchar);
        pBuf->line[nchar] = '\0';
       
        if (needTruncation) {
            pBuf->line[nchar - 3] = '\'';
            pBuf->line[nchar - 2] = ',';
            pBuf->line[nchar - 1] = '$';

            pLongBuf = pBuf;
            needTruncation = FALSE;
        }

        switch (inlineType) {
            case IS_STYLE:
                ListAddTail(&stylcm->inlineList, pBuf);
                break;
            case IS_GRAPHSTYLE:
                ListAddTail(&stylcm->inlineGraph, pBuf);
                break;
            case IS_PUTSTYLE:
                ListAddTail(&stylcm->putstyleHead, pBuf);
                break;
        }
    }
 
    /* Put an ENDLAYOUT keyword at the end of the buffer to tell */
    /* the parser where the LAYOUT statements end and the regular */
    /* stylesheet begins: */
    if (inlineType == IS_PUTSTYLE) {
        pBuf = (InlineBuf *)fcalloc(1, sizeof(InlineBuf));
        strcpy(pBuf->line, "ENDLAYOUT, $");
        ListAddTail(&stylcm->putstyleHead, pBuf);
    }
 
    if ((rc != 3) &&                    /* Not 'QUIT'? */
        (inlineType == IS_STYLE))
    {
        /* Tell y_fopen() that we have an in-line stylesheet: */
        memcpy(stylcm->ss_file, "FOCSTY  ", 8);
    }
 
    return rc;
}
0
Comment
Question by:starkman
  • 4
  • 3
7 Comments
 
LVL 53

Expert Comment

by:Infinity08
Comment Utility
>> However, I noticed that the above two memory errors reported by Purify both occured before the line of code that crashes.

At what lines ?
0
 

Author Comment

by:starkman
Comment Utility
The two memory errors reported by Purify occured at the following three lines of code, which are well before the crashing of line of code:  

1).
  if ( NULL == (oul = fcalloc( 1, 32767 )) )  /* SRKSRK */

2).
 memcpy( &oul[ dialog->ncpro ], &cmdTrailer,
                          offsetof(t_cmdTrailer,filler) );

3).
wrtstk(&i__1, envir->fstkdd, oul, &flag_, &ffstck);

Thank you for your prompt attention!
0
 
LVL 53

Accepted Solution

by:
Infinity08 earned 250 total points
Comment Utility
The fact that it runs fine in the debugger, but crashes when run normally, could indicate memory corruption.

The purify results indicate just that : an array overflow. So, as you suspected, that would be a good spot to start the investigation.

I can't find this line in the code you posted :

    memcpy( &oul[ dialog->ncpro ], &cmdTrailer, offsetof(t_cmdTrailer,filler) );

oul is a memory block of 32767 bytes. How is oul defined ?
What is the value of dialog->ncpro ?
What does offsetof(t_cmdTrailer,filler) return ?

The important thing is that this should be true :

    (&oul[ dialog->ncpro ] - &oul[0]) + offsetof(t_cmdTrailer,filler)    <=    32767

Purify seems to indicate that that's not the case.


For the third point, what does wrtstk() do ?
0
How your wiki can always stay up-to-date

Quip doubles as a “living” wiki and a project management tool that evolves with your organization. As you finish projects in Quip, the work remains, easily accessible to all team members, new and old.
- Increase transparency
- Onboard new hires faster
- Access from mobile/offline

 

Author Comment

by:starkman
Comment Utility
>>The important thing is that this should be true :

>>    (&oul[ dialog->ncpro ] - &oul[0]) + offsetof(t_cmdTrailer,filler)    <=    32767

>> Purify seems to indicate that that's not the case.

A quick test run of the program shows that  
(&oul[ dialog->ncpro ] - &oul[0]) + offsetof(t_cmdTrailer,filler)

indeed exeeded 32767 twice - it became 32780 and 32781, which seems to be consistent with what Purify reports about the 13 bytes illegal overwriting. I'll investigate more into this and let you know other information you requestd soon.
0
 
LVL 53

Expert Comment

by:Infinity08
Comment Utility
>> I'll investigate more into this and let you know other information you requestd soon.

Ok, keep us informed ...
0
 

Author Comment

by:starkman
Comment Utility
>>The important thing is that this should be true :

>>    (&oul[ dialog->ncpro ] - &oul[0]) + offsetof(t_cmdTrailer,filler)    <=    32767

>> Purify seems to indicate that that's not the case.

Sorry for submitting the addtional information late. Thank you very much for providing such a quick and accurate help! The problem has fixed after I added following overflow detection code before the above intruding line of code is called.

long curBytes, bytesToAppend, totalBytes, extraBytes;
Boolean overflow;

curBytes = dialog->ncpro;
bytesToAppend = offsetof(t_cmdTrailer,filler);
totalBytes = curBytes + bytesToAppend;
extraBytes = totalBytes - MAX_OUTL;
overflow = (extraBytes > 0);
if (overflow)                  
    dialog->ncpro -= extraBytes;

Here is the how "oul" is defined:
#define oul (fexecvars.outlin)
0
 

Author Comment

by:starkman
Comment Utility
Also, here is how "MAX_OUTL" is defined:
#define MAX_OUTL 32767
0

Featured Post

IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
how to connect an iphone application to mysql database 10 169
Picking random number 8 167
Problem with MFCApp 78 314
Detect CR LF to each line 12 137
An Outlet in Cocoa is a persistent reference to a GUI control; it connects a property (a variable) to a control.  For example, it is common to create an Outlet for the text field GUI control and change the text that appears in this field via that Ou…
Summary: This tutorial covers some basics of pointer, pointer arithmetic and function pointer. What is a pointer: A pointer is a variable which holds an address. This address might be address of another variable/address of devices/address of fu…
The goal of this video is to provide viewers with basic examples to understand and use structures in the C programming language.
The goal of this video is to provide viewers with basic examples to understand how to use strings and some functions related to them in the C programming language.

743 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

12 Experts available now in Live!

Get 1:1 Help Now