bugGNU Octave - Bugs: bug #56200, sscanf fourth output can be...

 
 

bug #56200: sscanf fourth output can be incorrect for decimal fields with a width specifier

Submitter:  Felipe G. Nievinski <fgnievinski>
Submitted:  Tue 23 Apr 2019 03:37:05 PM UTC
   
 
Category:  Octave Function Severity:  3 - Normal
Priority:  5 - Normal Item Group:  Incorrect Result
Status:  Fixed Assigned to:  None
Originator Name:  Open/Closed:  * Closed
Release:  * dev Operating System:  * Any
Fixed Release:  None Planned Release:  None
* Mandatory Fields

Add a New Comment Rich Markup
   

Sat 01 Jun 2019 04:01:00 PM UTC, comment #4: 

I went ahead and committed the patch https://hg.savannah.gnu.org/hgweb/octave/rev/8ea53aa9ac39.  Marking as fixed and closing report.

Rik <rik5>
Group administrator
Mon 27 May 2019 03:18:51 PM UTC, comment #3: 

Attached is a patch which works for me.  It has uncovered another problem.  With the patch, the position variable of the stream is correct, but the third output from sscanf should be an error message when the pattern fails to match.  I'll file a new bug report about that.

(file #46974)

Rik <rik5>
Group administrator
Sun 26 May 2019 03:25:56 PM UTC, comment #2: 

The issue is in oct-stream.cc.


  template <typename T>
  std::istream&
  octave_scan (std::istream& is, const scanf_format_elt& fmt, T *valptr)
  {
    if (fmt.width)
      {
        // Limit input to fmt.width characters by reading into a
        // temporary stringstream buffer.
        std::string tmp;

        is.width (fmt.width);
        is >> tmp;

        std::istringstream ss (tmp);

        octave_scan_1 (ss, fmt, valptr);
      }
    else
      octave_scan_1 (is, fmt, valptr);

    return is;
  }


When the format specifier contains a width, Octave reads WIDTH characters from the input stream and places them in to a temporary input stringstream object.  It then decodes that buffer with octave_scan_1.

However, the temporary read has altered the state of the istream object that is an input to this function.  In the case of


sscanf ('3a', '%6d', 1)


the attempted read of 6 characters advances the internal position pointer to the end of the string, and sets the eof flag on the stream.

One obvious way around this would be to manually set the position and flags of the stream 'is' based on the values of the position and flags in the temporary stringstream 'ss'.  In practice, this is going to make the code look pretty abstruse.

Maybe the solution is to update octave_scan_1 so that it can handle the width parameter of a format and we avoid creating a temporary istringstream object entirely.

The


Rik <rik5>
Group administrator
Thu 25 Apr 2019 06:23:46 AM UTC, comment #1: 

Confirmed. It seems to be caused by the combination of all 3 of

1. the %d conversion specifier,
2. a field width on the %d conversion, and
3. the adjacent non-digit, non-space character

For example,


>> [val, count, errmsg, nextpos] = sscanf ('3a', '%6d', 1)
val =  3
count =  1
errmsg =
nextpos =  3


As you showed, if %f or %g is used instead, it works correctly.


>> [val, count, errmsg, nextpos] = sscanf ('3a', '%6g', 1)
val =  3
count =  1
errmsg =
nextpos =  2


If the field width is removed, it also works correctly


>> [val, count, errmsg, nextpos] = sscanf ('3a', '%d', 1)
val =  3
count =  1
errmsg =
nextpos =  2


And if the integer is followed by a space instead of an alphabetic or punctuation character, it works correctly


>> [val, count, errmsg, nextpos] = sscanf ('3 a', '%6d', 1)
val =  3
count =  1
errmsg =
nextpos =  2


Mike Miller <mtmiller>
Group Member
Tue 23 Apr 2019 03:37:05 PM UTC, original submission:  

In Matlab, doing:

string = '1  9G02';
template = '%1d%3d';
size = 2;
[val, count, errmsg, nextpos] = sscanf (string, template, size)
display(['-' string(nextpos:end) '-'])

I get:

val =
     1
     9
count =
     2
errmsg =
  0×0 empty char array
nextpos =
     5
-G02-

Whereas in Octave 5, I get a different result for output nextpos:

   val =

       1
       9

    count =  2
    errmsg =
    nextpos =  7
-2-

The only way to get the correct result for nextpos in Octave is replacing the last decimal field specification for a float:

string = '1  9G02';
template = '%1d%3f';
size = 2;
[val, count, errmsg, nextpos] = sscanf (string, template, size)
display(['-' string(nextpos:end) '-'])

    val =

       1
       9

    count =  2
    errmsg =
    nextpos =  5
-G02-

I seems the problem is caused by the adjacent literal character "G".


Felipe G. Nievinski <fgnievinski>

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

Attached Files
file #46974:  bug56200.cset added by rik5 (2KiB - application/octet-stream)

 

Depends on the following items: None found

Digest:
   bug dependencies.

 

Carbon-Copy List
  • -email is unavailable- added by rik5 (Posted a comment)
  • -email is unavailable- added by rik5
  • -email is unavailable- added by fgnievinski (Submitted the item)
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only group members can vote.

     

    Follow 14 latest changes.

    Date Changed by Updated Field Previous Value => Replaced by
    2019-06-01 rik5 StatusPatch Submitted Fixed
        Open/ClosedOpen Closed
        Release5.1.0 dev
    2019-05-27 rik5 Dependencies- bugs #56396 is dependent
    2019-05-27 rik5 Attached File- Added bug56200.cset, #46974
        StatusConfirmed Patch Submitted
    2019-05-26 mtmiller Carbon-CopyRemoved mtmiller -
    2019-05-26 rik5 Summarysscanf fourth output might be incorrect for decimal fields sscanf fourth output can be incorrect for decimal fields with a width specifier
    2019-05-26 rik5 Carbon-Copy- Added jwe
        Carbon-Copy- Added mtmiller
    2019-04-25 mtmiller CategoryNone Octave Function
        Item GroupNone Incorrect Result
        StatusNone Confirmed
        Operating SystemMicrosoft Windows Any

    Back to the top

    Powered by Savane 3.13-4448.
    Corresponding source code