Solved

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

Posted on 2007-03-19
7
279 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
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 4
  • 3
7 Comments
 
LVL 53

Expert Comment

by:Infinity08
ID: 18752095
>> 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
ID: 18752135
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
ID: 18752201
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
Industry Leaders: 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!

 

Author Comment

by:starkman
ID: 18752653
>>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
ID: 18752699
>> I'll investigate more into this and let you know other information you requestd soon.

Ok, keep us informed ...
0
 

Author Comment

by:starkman
ID: 18851881
>>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
ID: 18852995
Also, here is how "MAX_OUTL" is defined:
#define MAX_OUTL 32767
0

Featured Post

Independent Software Vendors: 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!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Have you thought about creating an iPhone application (app), but didn't even know where to get started? Here's how: ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ ~ Important pre-programming comments: I’ve never tri…
Examines three attack vectors, specifically, the different types of malware used in malicious attacks, web application attacks, and finally, network based attacks.  Concludes by examining the means of securing and protecting critical systems and inf…
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 opening and writing to files in the C programming language.
Suggested Courses

738 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