Fix random_device to work with COW strings again

Instead of duplicating the initialization functions that take string,
add a new member taking a raw pointer that can be used to convert the
constructor token from the old string to the new.

Also fix "mt19337" typos in a testcase.

	* include/bits/random.h (random_device::_M_init(const char*, size_t)):
	Add new private member function.
	* src/c++11/cow-string-inst.cc (random_device::_M_init(const string&))
	(random_device::_M_init_pretr1(const string&)): Call new private
	member with string data.
	* src/c++11/random.cc (random_device::_M_init(const char*, size_t)):
	Define.
	* testsuite/26_numerics/random/random_device/cons/default-cow.cc: New
	test using COW strings.
	* testsuite/26_numerics/random/random_device/cons/default.cc: Generate
	a value from the device.
	* testsuite/26_numerics/random/random_device/cons/token.cc: Likewise.
	Fix typo in token string.

From-SVN: r271805
This commit is contained in:
Jonathan Wakely 2019-05-31 11:34:53 +01:00 committed by Jonathan Wakely
parent decc53df4e
commit aeedf07705
7 changed files with 86 additions and 58 deletions

View File

@ -1,3 +1,19 @@
2019-05-31 Jonathan Wakely <jwakely@redhat.com>
* include/bits/random.h (random_device::_M_init(const char*, size_t)):
Add new private member function.
* src/c++11/cow-string-inst.cc (random_device::_M_init(const string&))
(random_device::_M_init_pretr1(const string&)): Call new private
member with string data.
* src/c++11/random.cc (random_device::_M_init(const char*, size_t)):
Define.
* testsuite/26_numerics/random/random_device/cons/default-cow.cc: New
test using COW strings.
* testsuite/26_numerics/random/random_device/cons/default.cc: Generate
a value from the device.
* testsuite/26_numerics/random/random_device/cons/token.cc: Likewise.
Fix typo in token string.
2019-05-30 Nina Dinka Ranns <dinka.ranns@gmail.com>
LWG2788 basic_string spurious use of a default constructible allocator

View File

@ -1648,6 +1648,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
result_type _M_getval_pretr1();
double _M_getentropy() const noexcept;
void _M_init(const char*, size_t); // not exported from the shared library
union
{
struct

View File

@ -35,61 +35,15 @@
#ifdef _GLIBCXX_USE_C99_STDINT_TR1
#include <random>
#if defined __i386__ || defined __x86_64__
# include <cpuid.h>
#endif
#include <cstdio>
namespace std _GLIBCXX_VISIBILITY(default)
{
void
random_device::_M_init(const std::string& token)
{
const char *fname = token.c_str();
if (token == "default")
{
#if (defined __i386__ || defined __x86_64__) && defined _GLIBCXX_X86_RDRAND
unsigned int eax, ebx, ecx, edx;
// Check availability of cpuid and, for now at least, also the
// CPU signature for Intel's
if (__get_cpuid_max(0, &ebx) > 0 && ebx == signature_INTEL_ebx)
{
__cpuid(1, eax, ebx, ecx, edx);
if (ecx & bit_RDRND)
{
_M_file = nullptr;
return;
}
}
#endif
fname = "/dev/urandom";
}
else if (token != "/dev/urandom" && token != "/dev/random")
fail:
std::__throw_runtime_error(__N("random_device::"
"random_device(const std::string&)"));
_M_file = static_cast<void*>(std::fopen(fname, "rb"));
if (!_M_file)
goto fail;
}
{ _M_init(token.c_str(), token.length()); }
void
random_device::_M_init_pretr1(const std::string& token)
{
unsigned long __seed = 5489UL;
if (token != "mt19937")
{
const char* __nptr = token.c_str();
char* __endptr;
__seed = std::strtoul(__nptr, &__endptr, 0);
if (*__nptr == '\0' || *__endptr != '\0')
std::__throw_runtime_error(__N("random_device::random_device"
"(const std::string&)"));
}
_M_mt.seed(__seed);
}
{ _M_init(token.c_str(), token.length()); }
} // namespace
#endif

View File

@ -293,6 +293,18 @@ namespace std _GLIBCXX_VISIBILITY(default)
#endif
}
// Called by old ABI version of random_device::_M_init(const std::string&).
void
random_device::_M_init(const char* s, size_t len)
{
const std::string token(s, len);
#ifdef USE_MT19937
_M_init_pretr1(token);
#else
_M_init(token);
#endif
}
void
random_device::_M_fini()
{

View File

@ -0,0 +1,38 @@
// { dg-options "-D_GLIBCXX_USE_CXX11_ABI=0" }
// { dg-do run { target c++11 } }
// { dg-require-effective-target random_device }
// { dg-require-cstdint "" }
//
// Copyright (C) 2019 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
// <http://www.gnu.org/licenses/>.
// C++11 26.5.6 class random_device [rand.device]
#include <random>
#include <testsuite_hooks.h>
void
test01()
{
std::random_device x;
auto n [[gnu::unused]] = x();
}
int main()
{
test01();
}

View File

@ -21,8 +21,7 @@
// with this library; see the file COPYING3. If not see
// <http://www.gnu.org/licenses/>.
// 26.4.6 class random_device [rand.device]
// 26.4.2.2 Concept RandomNumberEngine [rand.concept.eng]
// C++11 26.5.6 class random_device [rand.device]
#include <random>
#include <testsuite_hooks.h>
@ -32,8 +31,11 @@ test01()
{
std::random_device x;
VERIFY( x.min() == std::numeric_limits<std::random_device::result_type>::min() );
VERIFY( x.max() == std::numeric_limits<std::random_device::result_type>::max() );
using result_type = std::random_device::result_type;
VERIFY( x.min() == std::numeric_limits<result_type>::min() );
VERIFY( x.max() == std::numeric_limits<result_type>::max() );
result_type n [[gnu::unused]] = x();
}
int main()

View File

@ -30,10 +30,9 @@ void
test01()
{
std::random_device x("default");
VERIFY( x.min() == std::numeric_limits<std::random_device::result_type>::min() );
VERIFY( x.max() == std::numeric_limits<std::random_device::result_type>::max() );
using result_type = std::random_device::result_type;
VERIFY( x.min() == std::numeric_limits<result_type>::min() );
VERIFY( x.max() == std::numeric_limits<result_type>::max() );
}
void
@ -42,6 +41,7 @@ test02()
#ifdef _GLIBCXX_USE_DEV_RANDOM
std::random_device x1("/dev/urandom");
std::random_device x2("/dev/random");
VERIFY( x1() != x2() );
#endif
}
@ -50,7 +50,7 @@ test03()
{
// At least one of these tokens should be valid.
const std::string tokens[] = {
"rdseed", "rdrand", "rand_s", "/dev/urandom", "/dev/random", "mt19337"
"rdseed", "rdrand", "rand_s", "/dev/urandom", "/dev/random", "mt19937"
};
int count = 0;
for (const std::string& token : tokens)
@ -71,21 +71,25 @@ void
test04()
{
bool can_use_mt19937 = true;
std::random_device::result_type xval;
try
{
std::random_device x("mt19937");
xval = x();
}
catch (const std::runtime_error&)
{
can_use_mt19937 = false;
}
// If "mt19337" is a valid token then numeric seeds should be too.
// If "mt19937" is a valid token then numeric seeds should be too.
if (can_use_mt19937)
{
std::random_device x1("0");
std::random_device x2("1234");
std::random_device x3("0xc0fefe");
VERIFY( xval != x1() );
VERIFY( x2() != x3() );
}
}