Ignore:
Timestamp:
Oct 5, 2023, 4:17:14 PM (10 months ago)
Author:
Michael Brooks <mlbrooks@…>
Branches:
master
Children:
4d860ea3
Parents:
b67b632
Message:

Fix read-to-variable-length-string cases when internal buffer fills.

Also fix read-to-cstring ability to give no-exception cases when an entire buffer fills.

The added test cases run, and fail, when run against prior libcfa.
Doing so illustrates a CFA-string-level bug.
Doing so illustrates a C-string-level changed semantics.

At the CFA-string level, the bug was, when reading strings of just the right length,
what should be two reads ("abc" then "def") gets mashed into one ("abcdef").
These cases are clearly bugs because a test program that just echoes chuncks of delimeted input would do so inaccurately.
They're just hard to drive because the relevant chunk lengths are implementation-dependent, and sometimes big.

At the C-string level, the semantic change concerns when to throw the cstring_length exception.
By this change, make the original semantics,
"An exception means the maximum number of characters was read," into
"An exception means that if the buffer were larger, then more characters would have been read."

The added test cases cover the respective stop conditions for manipulator state "%s", include, exclude, getline, and getline/delimiter.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • libcfa/src/collections/string_res.cfa

    rb67b632 r0860d9c  
    218218    // Read in chunks.  Often, one chunk is enough.  Keep the string that accumulates chunks last in the heap,
    219219    // so available room is rest of heap.  When a chunk fills the heap, force growth then take the next chunk.
    220     for (;;) {
     220    for (bool cont = true; cont; ) {
     221        cont = false;
     222
    221223        // Append dummy content to temp, forcing expansion when applicable (occurs always on subsequent loops)
    222224        // length 2 ensures room for at least one real char, plus scanf/pipe-cstr's null terminator
     
    228230        temp.Handle.ulink->EndVbyte -= 2;
    229231
    230         // rest of heap, less 1 byte for null terminator, is available to read into
    231         int lenReadable = (char*)temp.Handle.ulink->ExtVbyte - temp.Handle.ulink->EndVbyte - 1;
    232         assert (lenReadable >= 1);
     232        // rest of heap is available to read into
     233        int lenReadable = (char*)temp.Handle.ulink->ExtVbyte - temp.Handle.ulink->EndVbyte;
     234        assert (lenReadable >= 2);
    233235
    234236        // get bytes
    235         in | wdi( lenReadable + 1, lenReadable, temp.Handle.ulink->EndVbyte );
     237        try {
     238            in | wdi( lenReadable, temp.Handle.ulink->EndVbyte );
     239        } catch (cstring_length*) {
     240            cont = true;
     241        }
    236242        int lenWasRead = strlen(temp.Handle.ulink->EndVbyte);
    237243
     
    239245        temp.Handle.lnth += lenWasRead;
    240246        temp.Handle.ulink->EndVbyte += lenWasRead;
    241 
    242       if (lenWasRead < lenReadable) break;
    243247    }
    244248
Note: See TracChangeset for help on using the changeset viewer.