• C

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

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];

#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);
        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))
        /* 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);

        if (ptbcm->ptph == PTPHDY)

        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;
        /* 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);
            case IS_GRAPHSTYLE:
                ListAddTail(&stylcm->inlineGraph, pBuf);
            case IS_PUTSTYLE:
                ListAddTail(&stylcm->putstyleHead, pBuf);
    /* 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;
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

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

At what lines ?
starkmanAuthor Commented:
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:  

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

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

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

Thank you for your prompt attention!
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 ?

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Managing Security & Risk at the Speed of Business

Gartner Research VP, Neil McDonald & AlgoSec CTO, Prof. Avishai Wool, discuss the business-driven approach to automated security policy management, its benefits and how to align security policy management with business processes to address today's security challenges.

starkmanAuthor Commented:
>>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.
>> I'll investigate more into this and let you know other information you requestd soon.

Ok, keep us informed ...
starkmanAuthor Commented:
>>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)
starkmanAuthor Commented:
Also, here is how "MAX_OUTL" is defined:
#define MAX_OUTL 32767
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today

From novice to tech pro — start learning today.