Solved

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

Posted on 2007-03-19
7
274 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
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
Ransomware-A Revenue Bonanza for Service Providers

Ransomware – malware that gets on your customers’ computers, encrypts their data, and extorts a hefty ransom for the decryption keys – is a surging new threat.  The purpose of this eBook is to educate the reader about ransomware attacks.

 

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

Are your AD admin tools letting you down?

Managing Active Directory can get complicated.  Often, the native tools for managing AD are just not up to the task.  The largest Active Directory installations in the world have relied on one tool to manage their day-to-day administration tasks: Hyena. Start your trial today.

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
libcurl and C++ - Post JSON Data 8 1,302
How to align numbers in C using the %d 2 97
chcp 65001 File encoding 66 247
Concatenate two strings Last and First Name 10 60
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…
Preface I don't like visual development tools that are supposed to write a program for me. Even if it is Xcode and I can use Interface Builder. Yes, it is a perfect tool and has helped me a lot, mainly, in the beginning, when my programs were small…
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use for-loops in the C programming language.
The goal of this video is to provide viewers with basic examples to understand opening and reading files in the C programming language.

770 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