From d305d3c1a2bbf56dfcf6164a63122a8ee6edfd23 Mon Sep 17 00:00:00 2001 From: Howard Hinnant Date: Fri, 24 Aug 2012 21:20:56 +0000 Subject: [PATCH] =?UTF-8?q?Hyeon-Bin=20Jeong:=201.=20sync()=20should=20res?= =?UTF-8?q?et=20it=E2=80=99s=20external=20buffer=20pointers.=20Remaining?= =?UTF-8?q?=20characters=20should=20be=20discarded=20once=20sync()=20calle?= =?UTF-8?q?d.=20If=20don=E2=80=99t,=20garbage=20characters=20can=20be=20in?= =?UTF-8?q?serted=20to=20the=20front=20of=20external=20buffer=20in=20under?= =?UTF-8?q?flow().=20Because=20underflow()=20copies=20remaining=20characte?= =?UTF-8?q?rs=20in=20external=20buffer=20to=20it=E2=80=99s=20front.=20This?= =?UTF-8?q?=20results=20wrong=20characters=20insertion=20when=20seekpos()?= =?UTF-8?q?=20or=20seekoff()=20is=20called.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit this line should be inserted in sync() just before return: __extbufnext_ = __extbufend_ = __extbuf_; 2. sync() should use length() rather than out() to calculate offset. Reversing iterators and calling out() to calculate offset from behind is working fine in stateless character encoding. However, in stateful encoding, escape sequences could differ in length. As a result, out() could return wrong length. For example, if we have internal buffer converted from this external sequence: (capital letters mean escape sequence) … a a a a B b b b b out() produces this sequence. b b b b A a a a a Because out() inserts escape sequence A rather than B, result sequence doesn't match to external sequence. A and B could have different lengths, result offset could be wrong value too. length() method in codecvt is right for calculating offset, but it counts offset from the beginning of buffer. So it requires another state member variable to hold state before conversion. Fixes http://llvm.org/bugs/show_bug.cgi?id=13667 git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@162601 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/fstream | 40 +++++++++++++++++----------------------- 1 file changed, 17 insertions(+), 23 deletions(-) diff --git a/include/fstream b/include/fstream index aa78d85f3..7b6578f1e 100644 --- a/include/fstream +++ b/include/fstream @@ -234,6 +234,7 @@ private: FILE* __file_; const codecvt* __cv_; state_type __st_; + state_type __st_last_; ios_base::openmode __om_; ios_base::openmode __cm_; bool __owns_eb_; @@ -255,6 +256,7 @@ basic_filebuf<_CharT, _Traits>::basic_filebuf() __file_(0), __cv_(nullptr), __st_(), + __st_last_(), __om_(0), __cm_(0), __owns_eb_(false), @@ -293,6 +295,7 @@ basic_filebuf<_CharT, _Traits>::basic_filebuf(basic_filebuf&& __rhs) __file_ = __rhs.__file_; __cv_ = __rhs.__cv_; __st_ = __rhs.__st_; + __st_last_ = __rhs.__st_last_; __om_ = __rhs.__om_; __cm_ = __rhs.__cm_; __owns_eb_ = __rhs.__owns_eb_; @@ -325,6 +328,7 @@ basic_filebuf<_CharT, _Traits>::basic_filebuf(basic_filebuf&& __rhs) __rhs.__ibs_ = 0; __rhs.__file_ = 0; __rhs.__st_ = state_type(); + __rhs.__st_last_ = state_type(); __rhs.__om_ = 0; __rhs.__cm_ = 0; __rhs.__owns_eb_ = false; @@ -402,6 +406,7 @@ basic_filebuf<_CharT, _Traits>::swap(basic_filebuf& __rhs) _VSTD::swap(__file_, __rhs.__file_); _VSTD::swap(__cv_, __rhs.__cv_); _VSTD::swap(__st_, __rhs.__st_); + _VSTD::swap(__st_last_, __rhs.__st_last_); _VSTD::swap(__om_, __rhs.__om_); _VSTD::swap(__cm_, __rhs.__cm_); _VSTD::swap(__owns_eb_, __rhs.__owns_eb_); @@ -599,7 +604,7 @@ basic_filebuf<_CharT, _Traits>::underflow() size_t __nmemb = _VSTD::min(static_cast(__ibs_ - __unget_sz), static_cast(__extbufend_ - __extbufnext_)); codecvt_base::result __r; - state_type __svs = __st_; + __st_last_ = __st_; size_t __nr = fread((void*)__extbufnext_, 1, __nmemb, __file_); if (__nr != 0) { @@ -816,7 +821,7 @@ basic_filebuf<_CharT, _Traits>::seekpos(pos_type __sp, ios_base::openmode) return pos_type(off_type(-1)); if (fseeko(__file_, __sp, SEEK_SET)) return pos_type(off_type(-1)); - __st_ = __sp.state; + __st_ = __sp.state(); return __sp; } @@ -852,6 +857,8 @@ basic_filebuf<_CharT, _Traits>::sync() else if (__cm_ & ios_base::in) { off_type __c; + state_type __state = __st_last_; + bool __update_st = false; if (__always_noconv_) __c = this->egptr() - this->gptr(); else @@ -864,32 +871,19 @@ basic_filebuf<_CharT, _Traits>::sync() { if (this->gptr() != this->egptr()) { - reverse(this->gptr(), this->egptr()); - codecvt_base::result __r; - const char_type* __e = this->gptr(); - char* __extbe; - do - { - __r = __cv_->out(__st_, __e, this->egptr(), __e, - __extbuf_, __extbuf_ + __ebs_, __extbe); - switch (__r) - { - case codecvt_base::noconv: - __c += this->egptr() - this->gptr(); - break; - case codecvt_base::ok: - case codecvt_base::partial: - __c += __extbe - __extbuf_; - break; - default: - return -1; - } - } while (__r == codecvt_base::partial); + const int __off = __cv_->length(__state, __extbuf_, + __extbufnext_, + this->gptr() - this->eback()); + __c += __extbufnext_ - __extbuf_ - __off; + __update_st = true; } } } if (fseeko(__file_, -__c, SEEK_CUR)) return -1; + if (__update_st) + __st_ = __state; + __extbufnext_ = __extbufend_ = __extbuf_; this->setg(0, 0, 0); __cm_ = 0; }