From patchwork Tue Jul 25 20:43:26 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 793614 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Authentication-Results: ozlabs.org; spf=pass (mailfrom) smtp.mailfrom=gcc.gnu.org (client-ip=209.132.180.131; helo=sourceware.org; envelope-from=gcc-patches-return-458960-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="uP/D9fbW"; dkim-atps=neutral Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 3xH9F95HsKz9rvt for ; Wed, 26 Jul 2017 06:43:41 +1000 (AEST) DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; q=dns; s= default; b=Z2L1RnTmkzu2qlcEgZ+CmDSBrP28MPA6SNLaNQRacCwMI+6QPPBKv myXmJdwk2vOMTr4tCEXiuQtvDNyzQBXyZJ1NAR+te5soyFjuTt9NEFhn+qIubyEn vKygRrD2qlRYMJtkiIYqX1QIcA45Pc1pdIJtXS6TMvBUthQXmdMZHY= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:date :from:to:subject:message-id:mime-version:content-type; s= default; bh=MWZgpg207/rfHZ4J3G+7Zy1vAXA=; b=uP/D9fbW8Mqyaa/7lGKw P8rQ+Q/YTGtBQ/9smfvtJmN6Tx3/80nok7LzO5QfmRX6NGciMbqho3errR3SkWYe gdsB6e/oZ01RuCTqtZD5Gq2Q7iLXKUPHE+N4AdYgoPgr51fvXFvPbFsLjkfCLEAt y39ATGV1b/2heTaUtBISCgA= Received: (qmail 43652 invoked by alias); 25 Jul 2017 20:43:31 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 42549 invoked by uid 89); 25 Jul 2017 20:43:30 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-26.9 required=5.0 tests=BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RP_MATCHES_RCVD, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=Flip, clarified X-Spam-User: qpsmtpd, 2 recipients X-HELO: mx1.redhat.com Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 25 Jul 2017 20:43:28 +0000 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 53AA8C0587E8; Tue, 25 Jul 2017 20:43:27 +0000 (UTC) DMARC-Filter: OpenDMARC Filter v1.3.2 mx1.redhat.com 53AA8C0587E8 Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; dmarc=none (p=none dis=none) header.from=redhat.com Authentication-Results: ext-mx08.extmail.prod.ext.phx2.redhat.com; spf=pass smtp.mailfrom=jwakely@redhat.com Received: from localhost (unknown [10.33.36.81]) by smtp.corp.redhat.com (Postfix) with ESMTP id 019325D965; Tue, 25 Jul 2017 20:43:26 +0000 (UTC) Date: Tue, 25 Jul 2017 21:43:26 +0100 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH] PR libstdc++/53984 handle exceptions in basic_istream::sentry Message-ID: <20170725204326.GA28500@redhat.com> MIME-Version: 1.0 Content-Disposition: inline X-Clacks-Overhead: GNU Terry Pratchett User-Agent: Mutt/1.8.3 (2017-05-23) The standard says that formatted/unformatted input operations should catch any exceptions, set iostate bits in the istream, and rethrow if the exception mask says to do so. We're failing to do that when the exception happens in the istream::sentry constructor, while it extracts characters to skip whitespace. This means that input operations exit with an exception even when the mask says not to. The fix is simply to add a try/catch to the sentry constructor. I've also clarified some comments related to these semantics. PR libstdc++/53984 * include/bits/basic_ios.h (basic_ios::_M_setstate): Adjust comment. * include/bits/istream.tcc (basic_istream::sentry): Handle exceptions during construction. * include/std/istream: Adjust comments for formatted input functions and unformatted input functions. * testsuite/27_io/basic_fstream/53984.cc: New. * testsuite/27_io/basic_istream/sentry/char/53984.cc: New. Tested powerpc64le-linux, committed to trunk. commit a9a626df1531d0f06b147140b0f405f0847a0a42 Author: Jonathan Wakely Date: Tue Jul 25 19:12:22 2017 +0100 PR libstdc++/53984 handle exceptions in basic_istream::sentry PR libstdc++/53984 * include/bits/basic_ios.h (basic_ios::_M_setstate): Adjust comment. * include/bits/istream.tcc (basic_istream::sentry): Handle exceptions during construction. * include/std/istream: Adjust comments for formatted input functions and unformatted input functions. * testsuite/27_io/basic_fstream/53984.cc: New. * testsuite/27_io/basic_istream/sentry/char/53984.cc: New. diff --git a/libstdc++-v3/include/bits/basic_ios.h b/libstdc++-v3/include/bits/basic_ios.h index 318e41b..f0b8682 100644 --- a/libstdc++-v3/include/bits/basic_ios.h +++ b/libstdc++-v3/include/bits/basic_ios.h @@ -157,8 +157,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION setstate(iostate __state) { this->clear(this->rdstate() | __state); } - // Flip the internal state on for the proper state bits, then re - // throws the propagated exception if bit also set in + // Flip the internal state on for the proper state bits, then + // rethrows the propagated exception if bit also set in // exceptions(). void _M_setstate(iostate __state) diff --git a/libstdc++-v3/include/bits/istream.tcc b/libstdc++-v3/include/bits/istream.tcc index b390f74..92df9d1 100644 --- a/libstdc++-v3/include/bits/istream.tcc +++ b/libstdc++-v3/include/bits/istream.tcc @@ -48,28 +48,36 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { ios_base::iostate __err = ios_base::goodbit; if (__in.good()) - { - if (__in.tie()) - __in.tie()->flush(); - if (!__noskip && bool(__in.flags() & ios_base::skipws)) - { - const __int_type __eof = traits_type::eof(); - __streambuf_type* __sb = __in.rdbuf(); - __int_type __c = __sb->sgetc(); + __try + { + if (__in.tie()) + __in.tie()->flush(); + if (!__noskip && bool(__in.flags() & ios_base::skipws)) + { + const __int_type __eof = traits_type::eof(); + __streambuf_type* __sb = __in.rdbuf(); + __int_type __c = __sb->sgetc(); - const __ctype_type& __ct = __check_facet(__in._M_ctype); - while (!traits_type::eq_int_type(__c, __eof) - && __ct.is(ctype_base::space, - traits_type::to_char_type(__c))) - __c = __sb->snextc(); + const __ctype_type& __ct = __check_facet(__in._M_ctype); + while (!traits_type::eq_int_type(__c, __eof) + && __ct.is(ctype_base::space, + traits_type::to_char_type(__c))) + __c = __sb->snextc(); - // _GLIBCXX_RESOLVE_LIB_DEFECTS - // 195. Should basic_istream::sentry's constructor ever - // set eofbit? - if (traits_type::eq_int_type(__c, __eof)) - __err |= ios_base::eofbit; - } - } + // _GLIBCXX_RESOLVE_LIB_DEFECTS + // 195. Should basic_istream::sentry's constructor ever + // set eofbit? + if (traits_type::eq_int_type(__c, __eof)) + __err |= ios_base::eofbit; + } + } + __catch(__cxxabiv1::__forced_unwind&) + { + __in._M_setstate(ios_base::badbit); + __throw_exception_again; + } + __catch(...) + { __in._M_setstate(ios_base::badbit); } if (__in.good() && __err == ios_base::goodbit) _M_ok = true; diff --git a/libstdc++-v3/include/std/istream b/libstdc++-v3/include/std/istream index 1fa2555..233cc6b 100644 --- a/libstdc++-v3/include/std/istream +++ b/libstdc++-v3/include/std/istream @@ -150,9 +150,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * whatever data is appropriate for the type of the argument. * * If an exception is thrown during extraction, ios_base::badbit - * will be turned on in the stream's error state without causing an - * ios_base::failure to be thrown. The original exception will then - * be rethrown. + * will be turned on in the stream's error state (without causing an + * ios_base::failure to be thrown) and the original exception will + * be rethrown if badbit is set in the exceptions mask. */ //@{ @@ -286,9 +286,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION * by gcount(). * * If an exception is thrown during extraction, ios_base::badbit - * will be turned on in the stream's error state without causing an - * ios_base::failure to be thrown. The original exception will then - * be rethrown. + * will be turned on in the stream's error state (without causing an + * ios_base::failure to be thrown) and the original exception will + * be rethrown if badbit is set in the exceptions mask. */ /** diff --git a/libstdc++-v3/testsuite/27_io/basic_fstream/53984.cc b/libstdc++-v3/testsuite/27_io/basic_fstream/53984.cc new file mode 100644 index 0000000..e84072e --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_fstream/53984.cc @@ -0,0 +1,36 @@ +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-require-file-io "" } + +#include +#include + +void +test01() +{ + std::fstream in("."); + int x; + in >> x; + VERIFY( in.bad() ); +} + +int +main() +{ + test01(); +} diff --git a/libstdc++-v3/testsuite/27_io/basic_istream/sentry/char/53984.cc b/libstdc++-v3/testsuite/27_io/basic_istream/sentry/char/53984.cc new file mode 100644 index 0000000..9c08c72 --- /dev/null +++ b/libstdc++-v3/testsuite/27_io/basic_istream/sentry/char/53984.cc @@ -0,0 +1,41 @@ +// Copyright (C) 2017 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +#include +#include +#include + +struct SB : std::streambuf +{ + virtual int_type underflow() { throw 1; } +}; + +void +test01() +{ + SB sb; + std::istream is(&sb); + int i; + is >> i; + VERIFY( is.bad() ); +} + +int +main() +{ + test01(); +}