From patchwork Thu Mar 26 19:59:19 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jonathan Wakely X-Patchwork-Id: 455192 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org 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 2350C14012F for ; Fri, 27 Mar 2015 06:59:31 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass reason="1024-bit key; unprotected key" header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=E8ucRWAT; dkim-adsp=none (unprotected policy); dkim-atps=neutral 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=xyrADlANTzCEFfOukUnLRT5MUkzi0zeGPddxs39yagK8QKxm+90qw f+eR1oj1jneDDHqN/OAZMJQA9bOZTFGbmYH5Pn/F8RXupEduShWg7LbWMt8C5hzl NOhQ1kuUUO3J7BkJ4hkUXRyuPA1Ns+jXOTSv/HggD8bLjLuD707Veo= 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=s6DAM7+t46TbpZ8Yedv6MqJac/Q=; b=E8ucRWATF0rfD7a3mkN7 gEQd8xh0WJaet1PmvdlMd2x3he0uZ1oyxpo5Shh8JDzNrT7fOTe3lQYXJT3ClheD rCbQhMAnaEhLA50Hu3bFV8/KHHFur+1cI9rN1dyVYU2WPBWpQ1Pp9xmmDh+Jg8Q+ O8/DNqTeOFvfWxUYjcqjFMo= Received: (qmail 116086 invoked by alias); 26 Mar 2015 19:59:24 -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 116062 invoked by uid 89); 26 Mar 2015 19:59:23 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.0 required=5.0 tests=AWL, BAYES_00, SPF_HELO_PASS, T_RP_MATCHES_RCVD autolearn=ham version=3.3.2 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 (AES256-GCM-SHA384 encrypted) ESMTPS; Thu, 26 Mar 2015 19:59:21 +0000 Received: from int-mx11.intmail.prod.int.phx2.redhat.com (int-mx11.intmail.prod.int.phx2.redhat.com [10.5.11.24]) by mx1.redhat.com (Postfix) with ESMTPS id 99CEEAE5D9; Thu, 26 Mar 2015 19:59:20 +0000 (UTC) Received: from localhost (ovpn-116-96.ams2.redhat.com [10.36.116.96]) by int-mx11.intmail.prod.int.phx2.redhat.com (8.14.4/8.14.4) with ESMTP id t2QJxJbN014255; Thu, 26 Mar 2015 15:59:20 -0400 Date: Thu, 26 Mar 2015 19:59:19 +0000 From: Jonathan Wakely To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [patch] libstdc++/58038 libstdc++/60421 fix overflows in std::this_thread::sleep_for() Message-ID: <20150326195919.GM9755@redhat.com> MIME-Version: 1.0 Content-Disposition: inline User-Agent: Mutt/1.5.23 (2014-03-12) We have a couple of bugs where durations with unsigned representations result in negative or huge time_t values, which result in not sleeping at all or sleeping for billions of years (or merely for decades if you have a 32-bit time_t). This change simply returns early for time points in the past or negative durations. Tested x86_64-linux, powerpc64le-linux, committed to trunk. For stage 1 ... We can still overflow in this_thread::sleep_for() here: auto __s = chrono::duration_cast(__rtime); if __rtime uses a uint64_t rep and has a value larger than chrono::seconds::max(), and also here: static_cast(__s.count()), if time_t is 32-bit and __s has a value larger than it can hold. We should limit the __s value to duration::max() but detecting those overflows reliably is more complicated than we can manage for gcc5, and only happens for crazy durations anyway. We should also handle nanosleep() returning early and setting EINTR, and also loop in sleep_until() to handle clock adjustments: auto __now = _Clock::now(); if (_Clock::is_steady) { if (__now < __atime) sleep_for(__atime - __now); return; } while (__now < __atime) { sleep_for(__atime - __now); __now = _Clock::now(); } I also need to finish reviewing , and for similar problems. commit c6ffd1648328a4f2f2bbaac11378725c08409a95 Author: Jonathan Wakely Date: Thu Mar 5 23:43:08 2015 +0000 PR libstdc++/58038 PR libstdc++/60421 * include/std/thread (this_thread::sleep_for): Check for negative durations. (this_thread::sleep_until): Check for times in the past. * testsuite/30_threads/this_thread/58038.cc: New. * testsuite/30_threads/this_thread/60421.cc: New. diff --git a/libstdc++-v3/include/std/thread b/libstdc++-v3/include/std/thread index 2f9e69a..ebbda62 100644 --- a/libstdc++-v3/include/std/thread +++ b/libstdc++-v3/include/std/thread @@ -279,6 +279,8 @@ _GLIBCXX_END_NAMESPACE_VERSION inline void sleep_for(const chrono::duration<_Rep, _Period>& __rtime) { + if (__rtime <= __rtime.zero()) + return; auto __s = chrono::duration_cast(__rtime); auto __ns = chrono::duration_cast(__rtime - __s); #ifdef _GLIBCXX_USE_NANOSLEEP @@ -297,7 +299,11 @@ _GLIBCXX_END_NAMESPACE_VERSION template inline void sleep_until(const chrono::time_point<_Clock, _Duration>& __atime) - { sleep_for(__atime - _Clock::now()); } + { + auto __now = _Clock::now(); + if (__now < __atime) + sleep_for(__atime - __now); + } _GLIBCXX_END_NAMESPACE_VERSION } diff --git a/libstdc++-v3/testsuite/30_threads/this_thread/58038.cc b/libstdc++-v3/testsuite/30_threads/this_thread/58038.cc new file mode 100644 index 0000000..afa861c --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/this_thread/58038.cc @@ -0,0 +1,44 @@ +// Copyright (C) 2015 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-options "-std=gnu++11" } +// { dg-require-cstdint "" } +// { dg-require-time "" } + +#include +#include + +void +test01() +{ + auto now = std::chrono::system_clock::now(); + std::this_thread::sleep_until(now - 1ul * std::chrono::seconds(1)); +} + +void +test02() +{ + auto now = std::chrono::steady_clock::now(); + std::this_thread::sleep_until(now - 1ul * std::chrono::seconds(1)); +} + +int +main() +{ + test01(); + test02(); +} diff --git a/libstdc++-v3/testsuite/30_threads/this_thread/60421.cc b/libstdc++-v3/testsuite/30_threads/this_thread/60421.cc new file mode 100644 index 0000000..ecc4deb --- /dev/null +++ b/libstdc++-v3/testsuite/30_threads/this_thread/60421.cc @@ -0,0 +1,38 @@ +// Copyright (C) 2015 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-options "-std=gnu++11" } +// { dg-require-cstdint "" } +// { dg-require-time "" } + +#include +#include +#include + +void +test01() +{ + std::this_thread::sleep_for(std::chrono::seconds(0)); + std::this_thread::sleep_for(std::chrono::seconds(-1)); + std::this_thread::sleep_for(std::chrono::duration::zero()); +} + +int +main() +{ + test01(); +}