Author

Topic: unhandled exception with vs 2010, unicode related ? (Read 4563 times)

full member
Activity: 385
Merit: 110
This code seems to be at the hart of it:

I am not sure with __nullstring is ?

I am not sure if it is assigned to text.sz ?!?

If it is, then it could be some kind of security future to produce 0xccccccc pointer on purpose to trigger an exception on purpose.

Otherwise some weird happens... I think 0xccccccccc might actually be garbage so perhaps not a security feature.

This could mean the loop is simply flawed ?!? it doesn't check for a null terminator ?

                    if (text.sz == NULL) /* NULL passed, use special string */
                        text.sz = __nullstring;
                    p = text.sz;
                    while (i-- && *p)
                        ++p;

^ Seems a pretty simply bug/mistake ?!?

But not really... it crashes on the very first iteration ?

The P is already invalid when it enters the while loop ?!? How come ?

Very strange... perhaps some other code didn't produce a correct pointer, perhaps an argument/extraction was simply missing... and a garbage pointer was passed to this code section..

A bit strange... it's also kinda strange how visual studio suddenly stops displaying insight into the locals/variables... that kinda sux... if that kept working it would have been easier to make sense of it... so that a bit strange, mouse hover not working... looking at locals did still work somewhat... but less ideal strangely enough...  couldn't tell what was being executed with that if branch... it seemed to skip it... so probably not null passed in .sz... so some kind of garbage in sz !?!

Oh well my investigation will stop here, because a more secure version should be used according to Microsoft... hmmm... fixing other people's code kinda sux... Sad

I just want the damn thing to run ok ?! Gjez...

Yeah and I am probably not the right guy to go and try and fix this... it would be simple, just replace a string function.. but somebody else should really test it, since I am just a noob to bitcoin ?!? And I am now already facing these kind of buffer overrun/pointer problems ?!?!? Not cool ! Wink Smiley =D
full member
Activity: 385
Merit: 110
Interesting, somebody else already found this bug in output.c and mentions it in this link:

http://social.msdn.microsoft.com/Forums/en-NZ/vcgeneral/thread/00ff8bf8-df4d-4d5f-ae72-d998165cee26

and he is also capable of re-producing it pretty easily, not sure if it's exactly the same, but could be interesting:

I shall copy and paste his discovery in case the link goes down:

"
I have this:
 char *something="thisthing";

char buffer[128]={0};

sprintf_s(buffer,128,"%s", something[0]);  I get unhandled exception at some memory block. Access violation reading some memory location. The stack frame in VS shows _output_s_l() in output.c breaking at line 1643. Your input will be highly appreciated.
"

The others who respond to his discovery believe apperently that it's some kind of copieing issue, and that there is a missing null terminator...

Somebody seems to offer a solution.

"
Some other ways to copy a specified number of chars only:
 
sprintf_s(buffer,128,"%.4s", something); // copy max 4
 
memcpy_s(buffer, 128, something, 4); // always copy 4
 
With memcpy_s always ensure that there's a nul character
 at the end after the copy if you intend to use buffer as
 a C string. It does't add one automatically, while
 sprintf_s does.
"

Now back to bitcoin:

The question is now: Is the bug triggered by a missing null terminator ?!? Or is it something totally else ?!? Hmmmm...

And if the null terminator is missing ? Then how come ? hmm...
full member
Activity: 385
Merit: 110
Yup that big routine actually contains that section that bombs out:

#else  /* _UNICODE */
                if (flags & (FL_LONG|FL_WIDECHAR)) {
                    if (text.wz == NULL) /* NULL passed, use special string */
                        text.wz = __wnullstring;
                    bufferiswide = 1;
                    pwch = text.wz;
                    while ( i-- && *pwch )
                        ++pwch;
                    textlen = (int)(pwch - text.wz);
                    /* textlen now contains length in wide chars */
                } else {
                    if (text.sz == NULL) /* NULL passed, use special string */
                        text.sz = __nullstring;
                    p = text.sz;
                    while (i-- && *p)
                        ++p;
                    textlen = (int)(p - text.sz);    /* length of the string */
                }

#endif  /* _UNICODE */


The comments say something about: "tempting to use strlen" to find end of string... bleh...

and then it goes on... "but there might not be a null terminator thus  we must do... something else ? blablablabla".

And then somehow this unicode section above fucks up ?!?!?!?

Now the big question is:

WHY the frick is it executing unicode section Huh?

Isn't the input supposed to be ansi string ?!??

Maybe the weird format string is being interpreted as a unicode string ?!?!? Which was honestly my first guess at what was going on...

But I cannot imagine anybody making a blunder like that ?!?!?

Or maybe all strings in windows are secretly unicode strings ! Or are converted to unicode strings...

But my best bet is:

Somehow this routine gets confused and believes something is unicode while in reality it's ansi string... Hmmmm..

If I am correct about this, then this could be pretty interesting ! Wink

Because this could affect all other application which happen to use this function ! OUCH ! Wink Smiley

And then hackers will be using this little string, to trigger the buffer overrun ! or whatever it is, so if it is exploitable, then Microsoft just has another big problem on their hands ! Wink

To be fair to Micro-crap they did mention a more secure version is available
full member
Activity: 385
Merit: 110
Well not that I look at the code some more... it seems to not have to do so much with unicode, but more with the formatting... which is pretty insane ! Wink

All that code, just to print a bloody fricking number ?!? Oh man... that sux pretty bad, and now it's an exploitable buffer overrun probably... gjezzzzz....

Well, time to trace a little bit deeper to see which part of it actually produces the bom ! Wink Smiley
full member
Activity: 385
Merit: 110
It then seems to enter this function, which is just huge ! and complex ! and ugly ! and insane ! it's like oh my god ?! How can anybody program this shhhhiiittt ?!?

Now this truely makes me wonder if "unicode" was only invented to introduce exploitable system bugs for the chinese hackers ! YIKES ! Wink


    int __cdecl _output_s_l (
#endif  /* _SAFECRT_IMPL */
    FILE *stream,
#endif  /* POSITIONAL_PARAMETERS */

#endif  /* FORMAT_VALIDATIONS */
#endif  /* _UNICODE */

#endif  /* CPRFLAG */
    const _TCHAR *format,
#ifndef _SAFECRT_IMPL
    _locale_t plocinfo,
#endif  /* _SAFECRT_IMPL */
    va_list argptr
    )
{
    int hexadd=0;     /* offset to add to number to get 'a'..'f' */
    TCHAR ch;       /* character just read */
    int flags=0;      /* flag word -- see #defines above for flag values */
    enum STATE state;   /* current state */
    enum CHARTYPE chclass; /* class of current character */
    int radix;      /* current conversion radix */
    int charsout;   /* characters currently written so far, -1 = IO error */
    int fldwidth = 0;   /* selected field width -- 0 means default */
    int precision = 0;  /* selected precision  -- -1 means default */
    TCHAR prefix[2];    /* numeric prefix -- up to two characters */
    int prefixlen=0;  /* length of prefix -- 0 means no prefix */
    int capexp;     /* non-zero = 'E' exponent signifient, zero = 'e' */
    int no_output=0;  /* non-zero = prodcue no output for this specifier */
    union {
        char *sz;   /* pointer text to be printed, not zero terminated */
        wchar_t *wz;
        } text;

    int textlen;    /* length of the text in bytes/wchars to be printed.
                       textlen is in multibyte or wide chars if _UNICODE */
    union {
        char sz[BUFFERSIZE];
#ifdef _UNICODE
        wchar_t wz[BUFFERSIZE];
#endif  /* _UNICODE */
        } buffer;
    wchar_t wchar;                      /* temp wchar_t */
    int buffersize;                     /* size of text.sz (used only for the call to _cfltcvt) */
    int bufferiswide=0;         /* non-zero = buffer contains wide chars already */

#ifndef _SAFECRT_IMPL
    _LocaleUpdate _loc_update(plocinfo);
#endif  /* _SAFECRT_IMPL */

#ifdef POSITIONAL_PARAMETERS
    /* Used for parsing the format */
    const _TCHAR * saved_format = NULL;
    _TCHAR * end_pos = NULL;

    /* This is the structure which stores the values corresponding to
    each positional param */
    struct positional_param pos_value[_ARGMAX];

    int pass = 0;        /* Ctr for scanning the format string in diff passes */
    int noofpasses = 0;  /* Set to 2 for positional formats, otherwise 1      */
    int max_pos = -1;    /* Keeping track of the current max positional arg   */
    int type_pos = -1;   /* position of an arg denoting a type                */
    int width_pos = -1;  /* position of an arg denoting width                 */
    int precis_pos = -1; /* position of an arg denoting precision             */
    int format_type = FMT_TYPE_NOTSET; /* type of format string               */
#endif  /* POSITIONAL_PARAMETERS */

    char *heapbuf = NULL; /* non-zero = test.sz using heap buffer to be freed */

#ifndef CPRFLAG
    _VALIDATE_RETURN( (stream != NULL), EINVAL, -1);
#ifndef _UNICODE
    _VALIDATE_STREAM_ANSI_RETURN(stream, EINVAL, EOF);
#endif  /* _UNICODE */
#endif  /* CPRFLAG */
    _VALIDATE_RETURN( (format != NULL), EINVAL, -1);

    charsout = 0;       /* no characters written yet */
#ifdef POSITIONAL_PARAMETERS

    saved_format = format;

    for(pass = 0 ; pass < 2; ++pass)
    {

        if((pass == FORMAT_OUTPUT_PASS) && (format_type == FMT_TYPE_NONPOSITIONAL))
        {
            /* If in pass2, we still have format_type isn't positional, it means
            that we do not need a 2nd pass */
            break;
        }
#endif  /* POSITIONAL_PARAMETERS */
    textlen = 0;        /* no text yet */
    state = ST_NORMAL;  /* starting state */
    heapbuf = NULL;     /* not using heap-allocated buffer */
    buffersize = 0;
#ifdef POSITIONAL_PARAMETERS
    max_pos = -1;
    fldwidth = 0;
    precision = 0;
    format = saved_format;
    type_pos = -1;
    width_pos = -1;
    precis_pos = -1;

    /* All chars before the first format specifier get output in the first
    pass itself. Hence we have to reset format_type to FMT_TYPE_NOTSET to ensure
    that they do not get output again in the 2nd pass */
    format_type = FMT_TYPE_NOTSET;
#endif  /* POSITIONAL_PARAMETERS */

    /* main loop -- loop while format character exist and no I/O errors */
    while ((ch = *format++) != _T('\0') && charsout >= 0) {
#ifndef FORMAT_VALIDATIONS
        chclass = FIND_CHAR_CLASS(__lookuptable, ch);  /* find character class */
        state = FIND_NEXT_STATE(__lookuptable, chclass, state); /* find next state */
#else  /* FORMAT_VALIDATIONS */
        chclass = FIND_CHAR_CLASS(__lookuptable_s, ch);  /* find character class */
        state = FIND_NEXT_STATE(__lookuptable_s, chclass, state); /* find next state */

#ifdef POSITIONAL_PARAMETERS
        if((state == ST_PERCENT) && (*format != _T('%')))
        {
            if(format_type == FMT_TYPE_NOTSET)
            {
                /* We set the value of format_type when we hit the first type specifier */
                if(_tcstol(format, &end_pos, 10) > 0 && (*end_pos == POSITION_CHAR))
                {
                    if(pass == FORMAT_POSSCAN_PASS)
                    {
                        memset(pos_value,0,sizeof(pos_value));
                    }
                    format_type = FMT_TYPE_POSITIONAL;
                }
                else
                {
                    format_type = FMT_TYPE_NONPOSITIONAL;
                }
            }

            if(format_type == FMT_TYPE_POSITIONAL)
            {
                type_pos = _tcstol(format, &end_pos, 10) - 1;
                format = end_pos + 1;

                if(pass == FORMAT_POSSCAN_PASS)
                {
                    /* We don't redo the validations in the 2nd pass */
                    _VALIDATE_RETURN(((type_pos >= 0) && (*end_pos == POSITION_CHAR) && (type_pos < _ARGMAX)), EINVAL, -1);

                    /* Update max_pos with the current maximum pos argument */
                    max_pos = type_pos > max_pos ? type_pos : max_pos;
                }
            }

        }
        else
        {
            /* If state is ST_INVALID, that means an invalid format specifier */
                        if (state == ST_INVALID)
                                _VALIDATE_RETURN(("Incorrect format specifier", 0), EINVAL, -1);
        }
#else  /* POSITIONAL_PARAMETERS */
                if (state == ST_INVALID)
                _VALIDATE_RETURN(("Incorrect format specifier", 0), EINVAL, -1);
#endif  /* POSITIONAL_PARAMETERS */

#endif  /* FORMAT_VALIDATIONS */

        /* execute code for each state */
        switch (state) {

        case ST_NORMAL:

#ifdef POSITIONAL_PARAMETERS
            if(((pass == FORMAT_POSSCAN_PASS) && (format_type == FMT_TYPE_POSITIONAL))
            || ((pass == FORMAT_OUTPUT_PASS) && (format_type == FMT_TYPE_NOTSET)))
            {

                /* Do not output in the 1st pass, if we have already come across
                a positional format specifier. All chars before the first format
                specifier get output in the first pass itself. Hence we need to
                check the format_type to make sure that they don't get output
                again in the 2nd pass */
                    break;
            }
#endif  /* POSITIONAL_PARAMETERS */
        NORMAL_STATE:

            /* normal state -- just write character */
#ifdef _UNICODE
            bufferiswide = 1;
#else  /* _UNICODE */
            bufferiswide = 0;
#ifdef _SAFECRT_IMPL
            if (isleadbyte((unsigned char)ch)) {
#else  /* _SAFECRT_IMPL */
            if (_isleadbyte_l((unsigned char)ch, _loc_update.GetLocaleT())) {
#endif  /* _SAFECRT_IMPL */
                WRITE_CHAR(ch, &charsout);
                ch = *format++;
                /* don't fall off format string */
                _VALIDATE_RETURN( (ch != _T('\0')), EINVAL, -1);
            }
#endif  /* _UNICODE */
            WRITE_CHAR(ch, &charsout);
            break;

        case ST_PERCENT:
            /* set default value of conversion parameters */
            prefixlen = fldwidth = no_output = capexp = 0;
            flags = 0;
            precision = -1;
            bufferiswide = 0;   /* default */
            break;

        case ST_FLAG:
            /* set flag based on which flag character */
            switch (ch) {
            case _T('-'):
                flags |= FL_LEFT;   /* '-' => left justify */
                break;
            case _T('+'):
                flags |= FL_SIGN;   /* '+' => force sign indicator */
                break;
            case _T(' '):
                flags |= FL_SIGNSP; /* ' ' => force sign or space */
                break;
            case _T('#'):
                flags |= FL_ALTERNATE;  /* '#' => alternate form */
                break;
            case _T('0'):
                flags |= FL_LEADZERO;   /* '0' => pad with leading zeros */
                break;
            }
            break;

        case ST_WIDTH:
            /* update width value */
            if (ch == _T('*')) {
                /* get width from arg list */
#ifdef POSITIONAL_PARAMETERS
                if(format_type == FMT_TYPE_NONPOSITIONAL)
                {
#endif  /* POSITIONAL_PARAMETERS */
                fldwidth = get_int_arg(&argptr);
#ifdef POSITIONAL_PARAMETERS
                }
                else
                {
                    width_pos = _tcstol(format, &end_pos, 10) - 1;
                    format = end_pos + 1;

                    if(pass == FORMAT_POSSCAN_PASS)
                    {
                        _VALIDATE_RETURN(((width_pos >= 0) && (*end_pos == POSITION_CHAR) && (type_pos < _ARGMAX)), EINVAL, -1);

                        /* Update max_pos with the current maximum pos argument */
                        max_pos = width_pos > max_pos ? width_pos : max_pos;

                        STORE_ARGPTR(pos_value, e_int_arg, width_pos, ch, flags)
                        break;

                    }
                    else
                    {
                        /* get width from arg list */
                        GET_ARG(get_int_arg,pos_value[width_pos].arg_ptr, fldwidth, )
                    }

                }
#endif  /* POSITIONAL_PARAMETERS */
                if (fldwidth < 0) {
                    /* ANSI says neg fld width means '-' flag and pos width */
                    flags |= FL_LEFT;
                    fldwidth = -fldwidth;
                }
            }
            else {
                /* add digit to current field width */
                fldwidth = fldwidth * 10 + (ch - _T('0'));
            }
            break;

        case ST_DOT:
            /* zero the precision, since dot with no number means 0
               not default, according to ANSI */
            precision = 0;
            break;

        case ST_PRECIS:
            /* update precison value */
            if (ch == _T('*')) {
                /* get precision from arg list */
#ifdef POSITIONAL_PARAMETERS
                if(format_type == FMT_TYPE_NONPOSITIONAL)
                {
#endif  /* POSITIONAL_PARAMETERS */
                precision = get_int_arg(&argptr);
#ifdef POSITIONAL_PARAMETERS
                }
                else
                {
                    precis_pos = _tcstol(format, &end_pos, 10) - 1;
                    format = end_pos + 1;

                    if(pass == FORMAT_POSSCAN_PASS)
                    {
                        _VALIDATE_RETURN(((precis_pos >= 0) && (*end_pos == POSITION_CHAR) && (type_pos < _ARGMAX)), EINVAL, -1);

                        /* Update max_pos with the current maximum pos argument */
                        max_pos = precis_pos > max_pos ? precis_pos : max_pos;

                        STORE_ARGPTR(pos_value, e_int_arg, precis_pos, ch, flags)
                        break;
                    }
                    else
                    {
                        /* get width from arg list */
                        GET_ARG(get_int_arg,pos_value[precis_pos].arg_ptr, precision, )
                    }
                }
#endif  /* POSITIONAL_PARAMETERS */
                if (precision < 0)
                    precision = -1; /* neg precision means default */
            }
            else {
                /* add digit to current precision */
                precision = precision * 10 + (ch - _T('0'));
            }
            break;

        case ST_SIZE:
            /* just read a size specifier, set the flags based on it */
            switch (ch) {
            case _T('l'):
                /*
                 * In order to handle the ll case, we depart from the
                 * simple deterministic state machine.
                 */
                if (*format == _T('l'))
                {
                    ++format;
                    flags |= FL_LONGLONG;   /* 'll' => long long */
                }
                else
                {
                    flags |= FL_LONG;   /* 'l' => long int or wchar_t */
                }
                break;

            case _T('I'):
                /*
                 * In order to handle the I, I32, and I64 size modifiers, we
                 * depart from the simple deterministic state machine. The
                 * code below scans for characters following the 'I',
                 * and defaults to 64 bit on WIN64 and 32 bit on WIN32
                 */
#if PTR_IS_INT64
                flags |= FL_I64;    /* 'I' => __int64 on WIN64 systems */
#endif  /* PTR_IS_INT64 */
                if ( (*format == _T('6')) && (*(format + 1) == _T('4')) )
                {
                    format += 2;
                    flags |= FL_I64;    /* I64 => __int64 */
                }
                else if ( (*format == _T('3')) && (*(format + 1) == _T('2')) )
                {
                    format += 2;
                    flags &= ~FL_I64;   /* I32 => __int32 */
                }
                else if ( (*format == _T('d')) ||
                          (*format == _T('i')) ||
                          (*format == _T('o')) ||
                          (*format == _T('u')) ||
                          (*format == _T('x')) ||
                          (*format == _T('X')) )
                {
#ifdef POSITIONAL_PARAMETERS
    /* %I without 32/64 is platform dependent. We set FL_PTRSIZE to indicate
    this - this is used in the positional parameter reuse validation */
                    flags |= FL_PTRSIZE;
#else  /* POSITIONAL_PARAMETERS */
                   /*
                    * Nothing further needed.  %Id (et al) is
                    * handled just like %d, except that it defaults to 64 bits
                    * on WIN64.  Fall through to the next iteration.
                    */
#endif  /* POSITIONAL_PARAMETERS */
                }
                else {
                    state = ST_NORMAL;
                    goto NORMAL_STATE;
                }
                break;

            case _T('h'):
                flags |= FL_SHORT;  /* 'h' => short int or char */
                break;

            case _T('w'):
                flags |= FL_WIDECHAR;  /* 'w' => wide character */
                break;

            }
            break;

        case ST_TYPE:
            /* we have finally read the actual type character, so we       */
            /* now format and "print" the output.  We use a big switch     */
            /* statement that sets 'text' to point to the text that should */
            /* be printed, and 'textlen' to the length of this text.       */
            /* Common code later on takes care of justifying it and        */
            /* other miscellaneous chores.  Note that cases share code,    */
            /* in particular, all integer formatting is done in one place. */
            /* Look at those funky goto statements!                        */

            switch (ch) {

            case _T('C'):   /* ISO wide character */
                if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
#ifdef _UNICODE
                    flags |= FL_SHORT;
#else  /* _UNICODE */
                    flags |= FL_WIDECHAR;   /* ISO std. */
#endif  /* _UNICODE */
                /* fall into 'c' case */

            case _T('c'): {
                /* print a single character specified by int argument */
#ifdef _UNICODE
                bufferiswide = 1;
#ifdef POSITIONAL_PARAMETERS
                if(format_type == FMT_TYPE_NONPOSITIONAL)
                {
#endif  /* POSITIONAL_PARAMETERS */
                        wchar = (wchar_t) get_int_arg(&argptr);
#ifdef POSITIONAL_PARAMETERS
                }
                else
                {
                        _VALIDATE_RETURN(((type_pos>=0) && (type_pos<_ARGMAX)), EINVAL, -1);

                        if (pass == FORMAT_POSSCAN_PASS)
                        {
                                STORE_ARGPTR(pos_value, e_int_arg, type_pos, ch, flags)
                                break;
                        }
                        else
                        {
                                GET_ARG(get_int_arg,pos_value[type_pos].arg_ptr, wchar, (wchar_t))
                        }
                }
#endif  /* POSITIONAL_PARAMETERS */
                if (flags & FL_SHORT) {
                    /* format multibyte character */
                    /* this is an extension of ANSI */
                    char tempchar[2];
                    {
                        tempchar[0] = (char)(wchar & 0x00ff);
                        tempchar[1] = '\0';
                    }

#ifdef _SAFECRT_IMPL
                    if (_MBTOWC(buffer.wz,tempchar, MB_CUR_MAX) < 0)
#else  /* _SAFECRT_IMPL */
                    if (_mbtowc_l(buffer.wz,
                                  tempchar,
                                  _loc_update.GetLocaleT()->locinfo->mb_cur_max,
                                  _loc_update.GetLocaleT()) < 0)
#endif  /* _SAFECRT_IMPL */
                    {
                        /* ignore if conversion was unsuccessful */
                        no_output = 1;
                    }
                } else {
                    buffer.wz[0] = wchar;
                }
                text.wz = buffer.wz;
                textlen = 1;    /* print just a single character */
#else  /* _UNICODE */
                if (flags & (FL_LONG|FL_WIDECHAR)) {
                    errno_t e = 0;
#ifdef POSITIONAL_PARAMETERS
                    if(format_type == FMT_TYPE_NONPOSITIONAL)
                    {
#endif  /* POSITIONAL_PARAMETERS */
                    wchar = (wchar_t) get_short_arg(&argptr);
#ifdef POSITIONAL_PARAMETERS
                    }
                    else
                    {
                        _VALIDATE_RETURN(((type_pos>=0) && (type_pos<_ARGMAX)), EINVAL, -1);

                        if (pass == FORMAT_POSSCAN_PASS)
                        {
                            STORE_ARGPTR(pos_value, e_short_arg, type_pos, ch, flags)
                            break;
                        }
                        else
                        {
                            GET_ARG(get_short_arg,pos_value[type_pos].arg_ptr, wchar, (wchar_t))
                        }
                    }
#endif  /* POSITIONAL_PARAMETERS */
                    /* convert to multibyte character */
                    e = _WCTOMB_S(&textlen, buffer.sz, _countof(buffer.sz), wchar);

                    /* check that conversion was successful */
                    if (e != 0)
                        no_output = 1;
                } else {
                    /* format multibyte character */
                    /* this is an extension of ANSI */
                    unsigned short temp;
#ifdef POSITIONAL_PARAMETERS
                    if(format_type == FMT_TYPE_NONPOSITIONAL)
                    {
#endif  /* POSITIONAL_PARAMETERS */
                    temp = (unsigned short) get_int_arg(&argptr);
#ifdef POSITIONAL_PARAMETERS
                    }
                    else
                    {
                        _VALIDATE_RETURN(((type_pos>=0) && (type_pos<_ARGMAX)), EINVAL, -1);

                        if (pass == FORMAT_POSSCAN_PASS)
                        {
                            STORE_ARGPTR(pos_value, e_int_arg, type_pos, ch, flags)
                            break;
                        }
                        else
                        {
                            GET_ARG(get_int_arg,pos_value[type_pos].arg_ptr, temp, (unsigned short))
                        }
                    }
#endif  /* POSITIONAL_PARAMETERS */
                    {
                        buffer.sz[0] = (char) temp;
                        textlen = 1;
                    }
                }
                text.sz = buffer.sz;
#endif  /* _UNICODE */
            }
            break;

            case _T('Z'): {
                /* print a Counted String

                int i;
                char *p;       /* temps */
                struct _count_string {
                    short Length;
                    short MaximumLength;
                    char *Buffer;
                } *pstr;

#ifdef POSITIONAL_PARAMETERS
                if(format_type == FMT_TYPE_NONPOSITIONAL)
                {
#endif  /* POSITIONAL_PARAMETERS */
                pstr = (struct _count_string *)get_ptr_arg(&argptr);
#ifdef POSITIONAL_PARAMETERS
                }
                else
                {
                    _VALIDATE_RETURN(((type_pos>=0) && (type_pos<_ARGMAX)), EINVAL, -1);

                    if (pass == FORMAT_POSSCAN_PASS)
                    {
                        STORE_ARGPTR(pos_value, e_ptr_arg, type_pos, ch, flags)
                        break;
                    }
                    else
                    {
                        GET_ARG(get_ptr_arg,pos_value[type_pos].arg_ptr, pstr, (struct _count_string *) )
                    }
                }
#endif  /* POSITIONAL_PARAMETERS */
                if (pstr == NULL || pstr->Buffer == NULL) {
                    /* null ptr passed, use special string */
                    text.sz = __nullstring;
                    textlen = (int)strlen(text.sz);
                } else {
                    if (flags & FL_WIDECHAR) {
                        text.wz = (wchar_t *)pstr->Buffer;
                        textlen = pstr->Length / (int)sizeof(wchar_t);
                        bufferiswide = 1;
                    } else {
                        bufferiswide = 0;
                        text.sz = pstr->Buffer;
                        textlen = pstr->Length;
                    }
                }
            }
            break;

            case _T('S'):   /* ISO wide character string */
#ifndef _UNICODE
                if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
                    flags |= FL_WIDECHAR;
#else  /* _UNICODE */
                if (!(flags & (FL_SHORT|FL_LONG|FL_WIDECHAR)))
                    flags |= FL_SHORT;
#endif  /* _UNICODE */

            case _T('s'): {
                /* print a string --                            */
                /* ANSI rules on how much of string to print:   */
                /*   all if precision is default,               */
                /*   min(precision, length) if precision given. */
                /* prints '(null)' if a null string is passed   */

                int i;
                char *p;       /* temps */
                wchar_t *pwch;

                /* At this point it is tempting to use strlen(), but */
                /* if a precision is specified, we're not allowed to */
                /* scan past there, because there might be no null   */
                /* at all.  Thus, we must do our own scan.           */

                i = (precision == -1) ? INT_MAX : precision;
#ifdef POSITIONAL_PARAMETERS
                if(format_type == FMT_TYPE_NONPOSITIONAL)
                {
#endif  /* POSITIONAL_PARAMETERS */
                text.sz = (char *)get_ptr_arg(&argptr);
#ifdef POSITIONAL_PARAMETERS
                }
                else
                {
                    _VALIDATE_RETURN(((type_pos>=0) && (type_pos<_ARGMAX)), EINVAL, -1);

                    if (pass == FORMAT_POSSCAN_PASS)
                    {
                        STORE_ARGPTR(pos_value, e_ptr_arg, type_pos, ch, flags)
                        break;
                    }
                    else
                    {
                        GET_ARG(get_ptr_arg,pos_value[type_pos].arg_ptr, text.sz,(char *))
                    }
                }
#endif  /* POSITIONAL_PARAMETERS */

                /* scan for null upto i characters */
#ifdef _UNICODE
                if (flags & FL_SHORT) {
                    if (text.sz == NULL) /* NULL passed, use special string */
                        text.sz = __nullstring;
                    p = text.sz;
                    for (textlen=0; textlen#ifdef _SAFECRT_IMPL
                        if (isleadbyte((unsigned char)(*p)))
#else  /* _SAFECRT_IMPL */
                        if (_isleadbyte_l((unsigned char)(*p), _loc_update.GetLocaleT()))
#endif  /* _SAFECRT_IMPL */
                            ++p;
                        ++p;
                    }
                    /* textlen now contains length in multibyte chars */
                } else {
                    if (text.wz == NULL) /* NULL passed, use special string */
                        text.wz = __wnullstring;
                    bufferiswide = 1;
                    pwch = text.wz;
                    while (i-- && *pwch)
                        ++pwch;
                    textlen = (int)(pwch - text.wz);       /* in wchar_ts */
                    /* textlen now contains length in wide chars */
                }
#else  /* _UNICODE */
                if (flags & (FL_LONG|FL_WIDECHAR)) {
                    if (text.wz == NULL) /* NULL passed, use special string */
                        text.wz = __wnullstring;
                    bufferiswide = 1;
                    pwch = text.wz;
                    while ( i-- && *pwch )
                        ++pwch;
                    textlen = (int)(pwch - text.wz);
                    /* textlen now contains length in wide chars */
                } else {
                    if (text.sz == NULL) /* NULL passed, use special string */
                        text.sz = __nullstring;
                    p = text.sz;
                    while (i-- && *p)
                        ++p;
                    textlen = (int)(p - text.sz);    /* length of the string */
                }

#endif  /* _UNICODE */
            }
            break;


            case _T('n'): {
                /* write count of characters seen so far into */
                /* short/int/long thru ptr read from args */

                void *p;        /* temp */

#ifdef POSITIONAL_PARAMETERS
                if(format_type == FMT_TYPE_NONPOSITIONAL)
                {
#endif  /* POSITIONAL_PARAMETERS */
                p = get_ptr_arg(&argptr);
#ifdef POSITIONAL_PARAMETERS
                }
                else
                {
                    _VALIDATE_RETURN(((type_pos>=0) && (type_pos<_ARGMAX)), EINVAL, -1);

                    if (pass == FORMAT_POSSCAN_PASS)
                    {
                        STORE_ARGPTR(pos_value, e_ptr_arg, type_pos, ch, flags)
                        break;
                    }
                    else
                    {
                        GET_ARG(get_ptr_arg,pos_value[type_pos].arg_ptr,p,)
                    }
                }
#endif  /* POSITIONAL_PARAMETERS */

                /* if %n is disabled, we skip an arg and print 'n' */
                if ( !_get_printf_count_output() )
                {
                    _VALIDATE_RETURN(("'n' format specifier disabled", 0), EINVAL, -1);
                    break;
                }

                /* store chars out into short/long/int depending on flags */
#if !LONG_IS_INT
                if (flags & FL_LONG)
                    *(long *)p = charsout;
                else
#endif  /* !LONG_IS_INT */

#if !SHORT_IS_INT
                if (flags & FL_SHORT)
                    *(short *)p = (short) charsout;
                else
#endif  /* !SHORT_IS_INT */
                    *(int *)p = charsout;

                no_output = 1;              /* force no output */
            }
            break;

            case _T('E'):
            case _T('G'):
            case _T('A'):
                capexp = 1;                 /* capitalize exponent */
                ch += _T('a') - _T('A');    /* convert format char to lower */
                /* DROP THROUGH */
            case _T('e'):
            case _T('f'):
            case _T('g'):
            case _T('a'): {
                /* floating point conversion -- we call cfltcvt routines */
                /* to do the work for us.                                */
                flags |= FL_SIGNED;         /* floating point is signed conversion */
#ifdef POSITIONAL_PARAMETERS
                if((format_type == FMT_TYPE_POSITIONAL) && (pass == FORMAT_POSSCAN_PASS))
                {
                    _VALIDATE_RETURN(((type_pos>=0) && (type_pos<_ARGMAX)), EINVAL, -1);

#if !LONGDOUBLE_IS_DOUBLE

                    if (flags & FL_LONGDOUBLE)
                    {
                        STORE_ARGPTR(pos_value, e_longdouble_arg, type_pos, ch, flags)
                    }
                    else
#endif  /* !LONGDOUBLE_IS_DOUBLE */
                    {
                        STORE_ARGPTR(pos_value, e_double_arg, type_pos, ch, flags)
                    }

                    break;
                }
#endif  /* POSITIONAL_PARAMETERS */
                text.sz = buffer.sz;        /* put result in buffer */
                buffersize = BUFFERSIZE;

                /* compute the precision value */
                if (precision < 0)
                    precision = 6;          /* default precision: 6 */
                else if (precision == 0 && ch == _T('g'))
                    precision = 1;          /* ANSI specified */
                else if (precision > MAXPRECISION)
                    precision = MAXPRECISION;

                if (precision > BUFFERSIZE - _CVTBUFSIZE) {
                    /* conversion will potentially overflow local buffer */
                    /* so we need to use a heap-allocated buffer.        */
                    heapbuf = (char *)_malloc_crt(_CVTBUFSIZE + precision);
                    if (heapbuf != NULL)
                    {
                        text.sz = heapbuf;
                        buffersize = _CVTBUFSIZE + precision;
                    }
                    else
                        /* malloc failed, cap precision further */
                        precision = BUFFERSIZE - _CVTBUFSIZE;
                }

#ifdef _SAFECRT_IMPL
                /* for safecrt, we pass along the FL_ALTERNATE flag to _safecrt_cfltcvt */
                if (flags & FL_ALTERNATE)
                {
                    capexp |= FL_ALTERNATE;
                }
#endif  /* _SAFECRT_IMPL */

#if !LONGDOUBLE_IS_DOUBLE
                /* do the conversion */
                if (flags & FL_LONGDOUBLE) {
                    _LONGDOUBLE tmp;
#ifdef POSITIONAL_PARAMETERS
                    if(format_type == FMT_TYPE_NONPOSITIONAL)
                    {
#endif  /* POSITIONAL_PARAMETERS */
                    tmp=va_arg(argptr, _LONGDOUBLE);
#ifdef POSITIONAL_PARAMETERS
                    }
                    else
                    {
                        /* Will get here only for pass == FORMAT_OUTPUT_PASS because
                        pass == FORMAT_POSSCAN_PASS has a break Above */
                        va_list tmp_arg;
                        _ASSERTE(pass == FORMAT_OUTPUT_PASS);
              &nb
full member
Activity: 385
Merit: 110
I have traced it further to this function/piece of code in vsprintf.c:

#ifndef _SWPRINTFS_ERROR_RETURN_FIX
int __cdecl _vsnprintf (
        char *string,
        size_t count,
        const char *format,
        va_list ap
        )
{
#pragma warning(push)
#pragma warning(disable:4996) // Disable deprecation warning since calling function is also deprecated
    return _vsnprintf_l(string, count, format, NULL, ap);
#pragma warning(pop)
}
#endif  /* _SWPRINTFS_ERROR_RETURN_FIX */

The parameters are as follows:

string:  (the hexadecimal is probably a pointer to the long unitialized ? string)

0x004604bc "ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ"

count: 50000

format: 0x0046c88c "%s/blk%04d.dat"

It then seems to call this function, seems to be some attempt and providing some fix or so ?:

int __cdecl _vsnprintf_helper (
        OUTPUTFN outfn,
        char *string,
        size_t count,
        const char *format,
        _locale_t plocinfo,
        va_list ap
        )
#endif  /* _SWPRINTFS_ERROR_RETURN_FIX */
#endif  /* _COUNT_ */

{
        FILE str = { 0 };
        REG1 FILE *outfile = &str;
        REG2 int retval;

        _VALIDATE_RETURN( (format != NULL), EINVAL, -1);

#ifdef _COUNT_
        _VALIDATE_RETURN( (count == 0) || (string != NULL), EINVAL, -1 );
#else  /* _COUNT_ */
        _VALIDATE_RETURN( (string != NULL), EINVAL, -1 );
#endif  /* _COUNT_ */

#ifndef _COUNT_
        outfile->_cnt = MAXSTR;
#else  /* _COUNT_ */
        if(count>INT_MAX)
        {
            /* old-style functions allow any large value to mean unbounded */
            outfile->_cnt = INT_MAX;
        }
        else
        {
            outfile->_cnt = (int)count;
        }
#endif  /* _COUNT_ */

        outfile->_flag = _IOWRT|_IOSTRG;
        outfile->_ptr = outfile->_base = string;

#ifndef _SWPRINTFS_ERROR_RETURN_FIX
        retval = _output_l(outfile, format, plocinfo, ap );
#else  /* _SWPRINTFS_ERROR_RETURN_FIX */
        retval = outfn(outfile, format, plocinfo, ap );
#endif  /* _SWPRINTFS_ERROR_RETURN_FIX */

        if ( string==NULL)
            return(retval);

#ifndef _SWPRINTFS_ERROR_RETURN_FIX

        _putc_nolock('\0',outfile);

        return(retval);
#else  /* _SWPRINTFS_ERROR_RETURN_FIX */
        if((retval >= 0) && (_putc_nolock('\0',outfile) != EOF))
            return(retval);

        string[count - 1] = 0;

        if (outfile->_cnt < 0)
        {
            /* the buffer was too small; we return -2 to indicate truncation */
            return -2;
        }
        return -1;
#endif  /* _SWPRINTFS_ERROR_RETURN_FIX */
}





full member
Activity: 385
Merit: 110
Well this seems to be some bad news:

http://msdn.microsoft.com/en-us/library/1kt27hek(v=vs.80).aspx

Write formatted output using a pointer to a list of arguments. These functions are deprecated because more secure versions are available; see vsnprintf_s, _vsnprintf_s, _vsnprintf_s_l, _vsnwprintf_s, _vsnwprintf_s_l.

Apperently bitcoin is using "unsecure" (less secure) routine versions ! Wink Smiley

Maybe it's a little problem which can be quickly corrected, ofcourse I am not sure yet.

The link goes on about preventing "buffer overruns" lol Wink Smiley =DDDDD

full member
Activity: 385
Merit: 110
Something goes wrong in this function of bitcoin:

nFile parameter is 1
nBlockPas parameter is 786228988
pszMode parameter is 0x01d9ea2c pointer to "rb"

file variable is uninitialized and/or contains garbage and/or it's it's location: 0xcccccccc which seems to match the values in the exception...



FILE* OpenBlockFile(unsigned int nFile, unsigned int nBlockPos, const char* pszMode)
{
    if (nFile == -1)
        return NULL;

// *** Begin of CRASH ***
    FILE* file = fopen(strprintf("%s/blk%04d.dat", GetDataDir().c_str(), nFile).c_str(), pszMode);
// *** End of CRASH ***


    if (!file)
        return NULL;
    if (nBlockPos != 0 && !strchr(pszMode, 'a') && !strchr(pszMode, 'w'))
    {
        if (fseek(file, nBlockPos, SEEK_SET) != 0)
        {
            fclose(file);
            return NULL;
        }
    }
    return file;
}


strprintf looks a bit suspicious to me, it's routine is:

util.cpp a bitcoin file:

string strprintf(const std::string &format, ...)
{
    char buffer[50000];
    char* p = buffer;
    int limit = sizeof(buffer);
    int ret;
    loop
    {
        va_list arg_ptr;
        va_start(arg_ptr, format);
        ret = _vsnprintf(p, limit, format.c_str(), arg_ptr);
        va_end(arg_ptr);
        if (ret >= 0 && ret < limit)
            break;
        if (p != buffer)
            delete[] p;
        limit *= 2;
        p = new char[limit];
        if (p == NULL)
            throw std::bad_alloc();
    }
    string str(p, p+ret);
    if (p != buffer)
        delete[] p;
    return str;
}

Confirmed, there appears to a bug in this routine, not yet sure what the exact bug is but it's too funny ! Wink =D

I suspect this string printing function is trying to scan some input strings in ... or perhaps it's trying to make sense of the format specifier.

Whatever the case may be it's first parameter is:

format = "%s/blk%04d.dat"

^ this looks a bit suspicious, perhaps the function is getting confused Wink Smiley hmm..

Perhaps it's not a problem with the bitcoin function. I kinda suspected that already, since it must compile and build and work properly otherwise bitcoin could never work Wink

So my first suspicion that this is indeed a microsoft problem appears to be true, the problem is with this function call:


        ret = _vsnprintf(p, limit, format.c_str(), arg_ptr);

which seems to be some Microsoft function, I am not yet sure, if this is indeed a microsoft function.

I am also not yet sure if the parameters passed are valid or wrong, perhaps in a wrong format.

But let's suppose for a moment that it is valid, then this is pretty hilarius that would mean Microsoft has big fat bug in their poop Wink Smiley

But format.c_str() looks very suspicious to me.

It's probably returning an AnsiString ?

And perhaps vsn expects a unicode string ?!?

And thus something screw up... hmmm....

It not seems to be getting hard to debug this further:

Not yet sure what this is and if it can be stepped into further:

stdio.h:

#pragma warning(disable:4793)
__DEFINE_CPP_OVERLOAD_STANDARD_NFUNC_0_2_ARGLIST_EX(int, __RETURN_POLICY_SAME, _CRTIMP, _snprintf, _vsnprintf, _Pre_notnull_ _Post_maybez_ char, _Out_cap_(_Count) _Post_maybez_, char, _Dest, _In_ size_t, _Count, _In_z_ _Printf_format_string_ const char *, _Format)


^ stdio.h is used a lot, so this could be major bug, or perhaps wrong parameters as described above...  interesting...
full member
Activity: 385
Merit: 110
As I thought it happens again, kinda weird:


Bitcoin version -858993460.-858993460.-858993460.-858993460-beta
Default data directory C:\Users\Skybuck\AppData\Roaming\Bitcoin
Bound to port 8333
Loading addresses...
dbenv.open strLogDir=C:\Users\Skybuck\AppData\Roaming\Bitcoin/database strErrorF
ile=C:\Users\Skybuck\AppData\Roaming\Bitcoin/db.log
Loaded 88254 addresses
 addresses             45876ms
Loading block index...


Unhandled exception at 0x5e0313af (msvcr100d.dll) in BitcoinDatabaseExporter.exe: 0xC0000005: Access violation reading location 0xcccccccc.

Hmmm...
full member
Activity: 385
Merit: 110
Maybe this dll got linked because I added:

#ifdef _MSC_VER
#include "stdafx.h"

I thought maybe stdafx.h is needed to make console work.

I shall remove it again, and see if the exception happens again... there's probably something in there which is causing exceptions even without this include.

Gonna be interesting...
full member
Activity: 385
Merit: 110
Hello,

This is a bit strange:

This code seems to produce an unhandled exception when trying to load the block database:

output.c:

#else  /* _UNICODE */
                if (flags & (FL_LONG|FL_WIDECHAR)) {
                    if (text.wz == NULL) /* NULL passed, use special string */
                        text.wz = __wnullstring;
                    bufferiswide = 1;
                    pwch = text.wz;
                    while ( i-- && *pwch )
                        ++pwch;
                    textlen = (int)(pwch - text.wz);
                    /* textlen now contains length in wide chars */
                } else {
                    if (text.sz == NULL) /* NULL passed, use special string */
                        text.sz = __nullstring;
                    p = text.sz;
                    while (i-- && *p)
                        ++p;   // Skybuck: problem is here.
                    textlen = (int)(p - text.sz);    /* length of the string */
                }

#endif  /* _UNICODE */

This could be a buffer overrun in some kind of ms*.dll file...

Pretty scary ! Wink =D

More details:

Unhandled exception at 0x5db313af (msvcr100d.dll) in BitcoinDatabaseExporter.exe: 0xC0000005: Access violation reading location 0xcccccccc.

(BitcoinDatabaseExporter.exe is actually just bitcoind.exe) hmm...
Jump to: