Menu

#34 Empty GLUI_TextBox crashes on window 7

open
nobody
5
2012-09-05
2011-08-23
Anonymous
No

I was using glui on Ubuntu without any problems, but when I tried the same code on my Windows 7 it crashed.
I reduced the code to a few lines and I found out that it crashed when I created an empty TextBox.
When I add a text in the TextBox (with set_text) then the program will run, but it will still crash when the text is erased afterwards.

The crash occurs in glutMainLoop and I get a the error "Debug Assertion Failed!".
The file is ...\xstring on line 1575 with the expression "string subscript out of range".

Discussion

  • Nobody/Anonymous

    The issue seems to be that the windows implementation of std::string does slightly different range checking when getting a char at an index. On Linux, if you get the first char of an empty string it will return '\0'. On windows it just screams and dies. Running a release build doesn't crash but it does have a lot of unexpected behavior.

     
  • Nobody/Anonymous

    I too was running into this and have found the specific cause.

    In VS2010, the default debug project settings define the preprocessor directive
    _ITERATOR_DEBUG_LEVEL=2

    This causes code inside xstring to perform range checking on calls to string::operator[], like so:

    if _ITERATOR_DEBUG_LEVEL == 2

        if (this->_Mysize <= _Off)
    
            _DEBUG_ERROR("string subscript out of range");
    

    #elif _ITERATOR_DEBUG_LEVEL == 1
    _SCL_SECURE_VALIDATE_RANGE(_Off < this->_Mysize);
    #endif / _ITERATOR_DEBUG_LEVEL == 2 /

    The variable _Mysize apparently represents string length minus null characters - i.e. the value returned by calling string::length. Therefore the range check fails and
    throws an out of range exception.

    Solutions:
    In debug build configuration, in project properties -> C/C++ -> Preprocessor, add the following directive:

    _ITERATOR_DEBUG_LEVEL=0

    *note: this is probably not a good idea as the you will lose a number of iterator-related asserts across the entire project, but it is the quick and dirty way to get around the issue.

    The other way is to modify a few lines of glui_edittext.cpp to check for an empty string before attempting to access the 0-indexed character object of a string.

    For example, following lines starting at line 849 :

    for( i=start; i<=end; i++ )
    width += char_width( text[i] );

    should be modified to something like:

    if(!text.empty())
    for( i=start; i<=end; i++ )
    width += char_width( text[i] );

    There are a few more places in the source that should be modified in a similar way. I can post the source with all of my changes if someone wants it.

    Hope this helps someone :) Cheers!

     
  • Anonymous

    Anonymous - 2012-03-30

    Would you mind posting your glui fixes nobody :)? What other files need modified? I guess I can just keep updating the code till I find all the situations where the error arises.

     
  • horse-in-bathtub

    I am not a dev of the project, but wouldn't mind to help since I find that some things could be factored back in so I don't revisit them. Apologies for the bad formatting, I have no idea how to do it right. Attached file is nicer.

    /***** GLUI_EditText::substring_width() **/

    int GLUI_EditText::substring_width( int start, int end )
    {
    int i, width;

    width = 0;

    // JOHN: empty text
    if (start == end)
    return 0;

    for( i=start; i<=end; i++ )
    width += char_width( text[i] );

    return width;
    }

    /***** GLUI_EditText::update_substring_bounds() **/

    int GLUI_EditText::update_substring_bounds( void )
    {
    int box_width;
    int text_len = (int)text.length();
    int old_start, old_end;

    old_start = substring_start;
    old_end = substring_end;

    / Calculate the width of the usable area of the edit box /
    box_width = MAX( this->w - this->text_x_offset
    - 4 / 2 * the two-line box border /
    - 2 * GLUI_EDITTEXT_BOXINNERMARGINX, 0 );

    CLAMP( substring_end, 0, MAX(text_len-1,0) );
    CLAMP( substring_start, 0, MAX(text_len-1,0) );

    // JOHN: avoid checks for empty text
    if (text_len == 0) {
    return false; / bounds did not change /
    }

    /****** GLUI_EditText::draw_text() ***/

    void GLUI_EditText::draw_text( int x, int y )
    {
    GLUI_DRAWINGSENTINAL_IDIOM
    int text_x, i, sel_lo, sel_hi;

    // JOHN: empty text
    if (text.size() == 0)
    return;

    /***** GLUI_EditText::draw_insertion_pt() **/

    void GLUI_EditText::draw_insertion_pt( void )
    {
    int curr_x, i;

    if ( NOT can_draw() )
    return;

    / Don't draw insertion pt if control is disabled /
    if ( NOT enabled )
    return;

    if ( debug ) dump( stdout, "-> DRAW_INS_PT" );

    if ( sel_start != sel_end OR insertion_pt < 0 ) {
    return; / Don't draw insertion point if there is a current selection /
    }

    / printf( "insertion pt: %d\n", insertion_pt ); /

    curr_x = this->x_abs + text_x_offset
    + substring_width( substring_start, substring_end )
    + 2 / The edittext box has a 2-pixel margin /
    + GLUI_EDITTEXT_BOXINNERMARGINX; / plus this many pixels blank space
    between the text and the box
    /

    // JOHN: avoid repeat on zero char
    if (text.size() > 0)
    for( i=substring_end; i>=insertion_pt; i-- ) {
    curr_x -= char_width( text[i] );
    }

     
  • horse-in-bathtub

    Correction to the above. fixes: 1) Insert position was out of place and 2) no text caused greyed field