Bug 38399 - money_get<> read decimal point when frac_digits() <= 0
Summary: money_get<> read decimal point when frac_digits() <= 0
Status: RESOLVED FIXED
Alias: None
Product: gcc
Classification: Unclassified
Component: libstdc++ (show other bugs)
Version: 4.3.0
: P3 normal
Target Milestone: 4.4.0
Assignee: Paolo Carlini
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2008-12-04 13:39 UTC by Andrey Tsyvarev
Modified: 2008-12-05 18:25 UTC (History)
1 user (show)

See Also:
Host:
Target:
Build:
Known to work:
Known to fail:
Last reconfirmed: 2008-12-04 15:11:39


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Andrey Tsyvarev 2008-12-04 13:39:06 UTC
From description of moneypunct<> facet(22.2.6.3, p3):

The format of the numeric monetary value is a decimal number:

    value ::= units [ decimal-point [ digits ]] | decimal-point digits

if frac_digits() returns a positive value, or

    value ::= units

otherwise.

But the implementation of money_get<>::do_get() reads from input stream decimal point and digits after it and write them to the result(units or digits), even when frac_digits() return nonpositive value.

In similar situation with grouping, when grouping string indicates that grouping shouldn't not be applied, implementation stops read when it encounters thousands separator.

Example:

#include <locale>
#include <sstream>
#include <iostream>

using namespace std;

class my_moneypunct : public moneypunct<char>
{
protected:
    //this should disable fraction part of monetary value
    int do_frac_digits()const {return 0;}
};

int  main()
{
    locale loc(locale(), new my_moneypunct());
    stringstream ss("123.456");
    ss.imbue(loc);
    string digits;
    ios_base::iostate err;
    use_facet<money_get<char> >(loc).get(ss, 0, false, ss, err, digits);
    
    string rest(istreambuf_iterator<char>(ss), istreambuf_iterator<char>());
    cout << "digits is \"" << digits << "\"\n";
    cout << "rest of stream is \"" << rest << "\"\n";
    return 0;
}

[tester@Fedore8 money_get_frac_digits]$ g++ ./test.cpp && ./a.out
digits is "123456"
rest of stream is ""
[tester@Fedore8 money_get_frac_digits]$ g++ --version
g++ (GCC) 4.3.0 20080428 (Red Hat 4.3.0-8)
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Comment 1 Paolo Carlini 2008-12-04 15:11:39 UTC
Ok.
Comment 2 Paolo Carlini 2008-12-04 16:08:35 UTC
(In reply to comment #0)
>     use_facet<money_get<char> >(loc).get(ss, 0, false, ss, err, digits);
> 
>     string rest(istreambuf_iterator<char>(ss), istreambuf_iterator<char>());

Fixing this issue is trivial, but please double check the above way of using mony_get::get, which in general doesn't work with our implementation. Only the iterator returned by get correctly points to the current char: constructing after the get an istreambuf_iterator<char>(ss) doesn't work for that. So, please double check carefully and in case open a separate PR.
Comment 3 Andrey Tsyvarev 2008-12-05 09:53:33 UTC
Thanks for remark. It seemed for me, that iterator returned by get() and iterator constructed from stream directly are interchangeable. Now I see that it isn't so.

Then, example should be rewritten:

#include <locale>
#include <sstream>
#include <iostream>

using namespace std;

class my_moneypunct : public moneypunct<char>
{
protected:
    //this should disable fraction part of monetary value
    int do_frac_digits()const {return 0;}
};

int  main()
{
    locale loc(locale(), new my_moneypunct());
    stringstream ss("123.455");
    ss.imbue(loc);
    string digits;
    ios_base::iostate err;
    istreambuf_iterator<char> iter = 
    	use_facet<money_get<char> >(loc).get(ss, 0, false, ss, err, digits);
    
    string rest = string(iter, istreambuf_iterator<char>());
    cout << "digits is \"" << digits << "\"\n";
    cout << "rest of stream is \"" << rest << "\"\n";
    return 0;
}
Output doesn't change.
Comment 4 Paolo Carlini 2008-12-05 09:59:03 UTC
(In reply to comment #3)
> Thanks for remark.

You are welcome. By the way, since in general you are so kind to report very accurate and to the point issues, I would appreciate if you could also add testcases more similar to what we already have in the testsuite (so, for example, no outputs, no use of iostreams, asserts instead; etc.). That would greatly speed up the whole process! Thanks again.
Comment 5 paolo@gcc.gnu.org 2008-12-05 18:24:54 UTC
Subject: Bug 38399

Author: paolo
Date: Fri Dec  5 18:23:39 2008
New Revision: 142487

URL: http://gcc.gnu.org/viewcvs?root=gcc&view=rev&rev=142487
Log:
2008-12-05  Paolo Carlini  <paolo.carlini@oracle.com>

	PR libstdc++/38399
	* include/bits/locale_facets_nonio.tcc (money_get<>::
	_M_extract(iter_type, iter_type, ios_base&, ios_base::iostate&,
	string&)): Fix, reject decimal point when frac_digits <= 0.
	* testsuite/22_locale/money_get/get/char/38399.cc: New.
	* testsuite/22_locale/money_get/get/wchar_t/38399.cc: Likewise.
	* testsuite/22_locale/money_get/get/char/5.cc: Adjust.
	* testsuite/22_locale/money_get/get/wchar_t/5.cc: Likewise.

Added:
    trunk/libstdc++-v3/testsuite/22_locale/money_get/get/char/38399.cc
    trunk/libstdc++-v3/testsuite/22_locale/money_get/get/wchar_t/38399.cc
Modified:
    trunk/libstdc++-v3/ChangeLog
    trunk/libstdc++-v3/include/bits/locale_facets_nonio.tcc
    trunk/libstdc++-v3/testsuite/22_locale/money_get/get/char/5.cc
    trunk/libstdc++-v3/testsuite/22_locale/money_get/get/wchar_t/5.cc

Comment 6 Paolo Carlini 2008-12-05 18:25:43 UTC
Fixed for 4.4.0.