Make powerpc-nofpu floating-point state thread-local (bug 15483).

This commit is contained in:
Joseph Myers 2013-11-19 13:39:56 +00:00
parent b5449b1296
commit 73c1ce4fdb
22 changed files with 389 additions and 75 deletions

View File

@ -1,3 +1,70 @@
2013-11-19 Joseph Myers <joseph@codesourcery.com>
[BZ #15483]
* sysdeps/powerpc/nofpu/sim-full.c (__sim_exceptions): Change to
thread-local __sim_exceptions_thread and global
__sim_exceptions_global.
(__sim_disabled_exceptions): Change to thread-local
__sim_disabled_exceptions_thread and global
__sim_disabled_exceptions_global.
(__sim_round_mode): Change to thread-local __sim_round_mode_thread
and global __sim_round_mode_global.
(__simulate_exceptions): Use thread-local floating-point state and
set global state from it as needed.
* sysdeps/powerpc/nofpu/Versions (GLIBC_PRIVATE): Add
__sim_exceptions_thread, __sim_disabled_exceptions_thread and
__sim_round_mode_thread.
* sysdeps/powerpc/nofpu/soft-supp.h: Include <shlib-compat.h>.
(__sim_exceptions): Change to thread-local __sim_exceptions_thread
and global __sim_exceptions_global.
(__sim_disabled_exceptions): Change to thread-local
__sim_disabled_exceptions_thread and global
__sim_disabled_exceptions_global.
(__sim_round_mode): Change to thread-local __sim_round_mode_thread
and global __sim_round_mode_global.
[SIM_GLOBAL_COMPAT] (SIM_COMPAT_SYMBOL): New macro.
(SIM_SET_GLOBAL): Likewise.
* sysdeps/powerpc/soft-fp/sfp-machine.h
[!(__NO_FPRS__ && !_SOFT_FLOAT)] (FP_ROUNDMODE): Use
__sim_round_mode_thread.
[!(__NO_FPRS__ && !_SOFT_FLOAT)] (FP_TRAPPING_EXCEPTIONS): Use
__sim_disabled_exceptions_thread.
(__sim_exceptions): Change to __sim_exceptions_thread.
(__sim_disabled_exceptions): Change to
__sim_disabled_exceptions_thread.
(__sim_round_mode): Change to __sim_round_mode_thread.
* sysdeps/powerpc/nofpu/fclrexcpt.c (__feclearexcept): Use
thread-local floating-point state and set global state from it as
needed.
* sysdeps/powerpc/nofpu/fedisblxcpt.c (fedisableexcept): Likewise.
* sysdeps/powerpc/nofpu/feenablxcpt.c: Include "soft-supp.h".
(__sim_disabled_exceptions): Remove extern declaration.
(feenableexcept): Use thread-local floating-point state and set
global state from it as needed.
* sysdeps/powerpc/nofpu/fegetenv.c (__sim_exceptions): Remove
extern declaration.
(__sim_disabled_exceptions): Likewise.
(__sim_round_mode): Likewise.
(__fegetenv): Use thread-local floating-point state.
* sysdeps/powerpc/nofpu/fegetexcept.c (fegetexcept): Likewise.
* sysdeps/powerpc/nofpu/fegetround.c (fegetround): Likewise.
* sysdeps/powerpc/nofpu/fesetenv.c (__fesetenv): Use thread-local
floating-point state and set global state from it as needed.
* sysdeps/powerpc/nofpu/fesetround.c (fesetround): Likewise.
* sysdeps/powerpc/nofpu/feupdateenv.c (__feupdateenv): Likewise.
* sysdeps/powerpc/nofpu/fgetexcptflg.c (__fegetexceptflag):
Likewise.
* sysdeps/powerpc/nofpu/fraiseexcpt.c (__feraiseexcept): Likewise.
* sysdeps/powerpc/nofpu/fsetexcptflg.c (__fesetexceptflag):
Likewise.
sysdeps/powerpc/nofpu/ftestexcept.c (fetestexcept): Likewise.
* sysdeps/powerpc/nofpu/get-rounding-mode.h (get_rounding_mode):
Use __sim_round_mode_thread.
* math/test-fenv-tls.c: New file.
* math/Makefile (tests): Add test-fenv-tls.
($(objpfx)test-fenv-tls): Depend on
$(common-objpfx)nptl/libpthread.so.
2013-11-19 Andreas Schwab <schwab@suse.de>
* locale/programs/locale.c (show_info): Decode wordarray elements.

17
NEWS
View File

@ -11,14 +11,15 @@ Version 2.19
156, 387, 431, 832, 2801, 7003, 9954, 10253, 10278, 11087, 13028, 13982,
13985, 14029, 14143, 14155, 14547, 14699, 14752, 14876, 14910, 15048,
15218, 15277, 15308, 15362, 15374, 15400, 15427, 15522, 15531, 15532,
15608, 15609, 15610, 15632, 15640, 15670, 15672, 15680, 15681, 15723,
15734, 15735, 15736, 15748, 15749, 15754, 15760, 15763, 15764, 15797,
15799, 15825, 15844, 15847, 15849, 15855, 15856, 15857, 15859, 15867,
15886, 15887, 15890, 15892, 15893, 15895, 15897, 15905, 15909, 15917,
15919, 15921, 15923, 15939, 15948, 15963, 15966, 15985, 15988, 15997,
16032, 16034, 16036, 16037, 16041, 16055, 16071, 16072, 16074, 16078,
16103, 16112, 16143, 16144, 16146, 16150, 16151, 16153, 16167, 16172.
15218, 15277, 15308, 15362, 15374, 15400, 15427, 15483, 15522, 15531,
15532, 15608, 15609, 15610, 15632, 15640, 15670, 15672, 15680, 15681,
15723, 15734, 15735, 15736, 15748, 15749, 15754, 15760, 15763, 15764,
15797, 15799, 15825, 15844, 15847, 15849, 15855, 15856, 15857, 15859,
15867, 15886, 15887, 15890, 15892, 15893, 15895, 15897, 15905, 15909,
15917, 15919, 15921, 15923, 15939, 15948, 15963, 15966, 15985, 15988,
15997, 16032, 16034, 16036, 16037, 16041, 16055, 16071, 16072, 16074,
16078, 16103, 16112, 16143, 16144, 16146, 16150, 16151, 16153, 16167,
16172.
* CVE-2012-4412 The strcoll implementation caches indices and rules for
large collation sequences to optimize multiple passes. This cache

View File

@ -90,7 +90,7 @@ tests = test-matherr test-fenv atest-exp atest-sincos atest-exp2 basic-test \
test-misc test-fpucw test-fpucw-ieee tst-definitions test-tgmath \
test-tgmath-ret bug-nextafter bug-nexttoward bug-tgmath1 \
test-tgmath-int test-tgmath2 test-powl tst-CMPLX tst-CMPLX2 test-snan \
$(tests-static)
test-fenv-tls $(tests-static)
tests-static = test-fpucw-static test-fpucw-ieee-static
# We do the `long double' tests only if this data type is available and
# distinct from `double'.
@ -232,3 +232,4 @@ gmp-objs = $(patsubst %,$(common-objpfx)stdlib/%.o,\
$(objpfx)atest-exp: $(gmp-objs)
$(objpfx)atest-sincos: $(gmp-objs)
$(objpfx)atest-exp2: $(gmp-objs)
$(objpfx)test-fenv-tls: $(common-objpfx)nptl/libpthread.so

208
math/test-fenv-tls.c Normal file
View File

@ -0,0 +1,208 @@
/* Test floating-point environment is thread-local.
Copyright (C) 2013 Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, see
<http://www.gnu.org/licenses/>. */
#include <fenv.h>
#include <pthread.h>
#include <stdio.h>
#include <stdint.h>
#define TEST_ONE_RM(RM) \
do \
{ \
if (fesetround (RM) == 0) \
{ \
rm = fegetround (); \
if (rm != RM) \
{ \
printf ("expected " #RM ", got %d\n", rm); \
ret = 1; \
} \
} \
} \
while (0)
static void *
test_round (void *arg)
{
intptr_t ret = 0;
for (int i = 0; i < 10000; i++)
{
int rm;
#ifdef FE_DOWNWARD
TEST_ONE_RM (FE_DOWNWARD);
#endif
#ifdef FE_TONEAREST
TEST_ONE_RM (FE_TONEAREST);
#endif
#ifdef FE_TOWARDZERO
TEST_ONE_RM (FE_TOWARDZERO);
#endif
#ifdef FE_UPWARD
TEST_ONE_RM (FE_UPWARD);
#endif
}
return (void *) ret;
}
#define TEST_ONE_RAISE(EX) \
do \
{ \
if (feraiseexcept (EX) == 0) \
if (fetestexcept (EX) != EX) \
{ \
printf (#EX " not raised\n"); \
ret = 1; \
} \
if (feclearexcept (FE_ALL_EXCEPT) == 0) \
if (fetestexcept (FE_ALL_EXCEPT) != 0) \
{ \
printf ("exceptions not all cleared\n"); \
ret = 1; \
} \
} \
while (0)
static void *
test_raise (void *arg)
{
intptr_t ret = 0;
for (int i = 0; i < 10000; i++)
{
#ifdef FE_DIVBYZERO
TEST_ONE_RAISE (FE_DIVBYZERO);
#endif
#ifdef FE_INEXACT
TEST_ONE_RAISE (FE_INEXACT);
#endif
#ifdef FE_INVALID
TEST_ONE_RAISE (FE_INVALID);
#endif
#ifdef FE_OVERFLOW
TEST_ONE_RAISE (FE_OVERFLOW);
#endif
#ifdef UNDERFLOW
TEST_ONE_RAISE (FE_UNDERFLOW);
#endif
}
return (void *) ret;
}
#define TEST_ONE_ENABLE(EX) \
do \
{ \
if (feenableexcept (EX) != -1) \
if (fegetexcept () != EX) \
{ \
printf (#EX " not enabled\n"); \
ret = 1; \
} \
if (fedisableexcept (EX) != -1) \
if (fegetexcept () != 0) \
{ \
printf ("exceptions not all disabled\n"); \
ret = 1; \
} \
} \
while (0)
static void *
test_enable (void *arg)
{
intptr_t ret = 0;
for (int i = 0; i < 10000; i++)
{
#ifdef FE_DIVBYZERO
TEST_ONE_ENABLE (FE_DIVBYZERO);
#endif
#ifdef FE_INEXACT
TEST_ONE_ENABLE (FE_INEXACT);
#endif
#ifdef FE_INVALID
TEST_ONE_ENABLE (FE_INVALID);
#endif
#ifdef FE_OVERFLOW
TEST_ONE_ENABLE (FE_OVERFLOW);
#endif
#ifdef UNDERFLOW
TEST_ONE_ENABLE (FE_UNDERFLOW);
#endif
}
return (void *) ret;
}
static int
do_test (void)
{
int ret = 0;
void *vret;
pthread_t thread_id;
int pret;
pret = pthread_create (&thread_id, NULL, test_round, NULL);
if (pret != 0)
{
printf ("pthread_create failed: %d\n", pret);
return 1;
}
vret = test_round (NULL);
ret |= (intptr_t) vret;
pret = pthread_join (thread_id, &vret);
if (pret != 0)
{
printf ("pthread_join failed: %d\n", pret);
return 1;
}
ret |= (intptr_t) vret;
pret = pthread_create (&thread_id, NULL, test_raise, NULL);
if (pret != 0)
{
printf ("pthread_create failed: %d\n", pret);
return 1;
}
vret = test_raise (NULL);
ret |= (intptr_t) vret;
pret = pthread_join (thread_id, &vret);
if (pret != 0)
{
printf ("pthread_join failed: %d\n", pret);
return 1;
}
ret |= (intptr_t) vret;
pret = pthread_create (&thread_id, NULL, test_enable, NULL);
if (pret != 0)
{
printf ("pthread_create failed: %d\n", pret);
return 1;
}
vret = test_enable (NULL);
ret |= (intptr_t) vret;
pret = pthread_join (thread_id, &vret);
if (pret != 0)
{
printf ("pthread_join failed: %d\n", pret);
return 1;
}
ret |= (intptr_t) vret;
return ret;
}
#define TEST_FUNCTION do_test ()
#include "../test-skeleton.c"

View File

@ -17,4 +17,9 @@ libc {
__gtdf2; __gtsf2;
__ltdf2; __ltsf2;
}
GLIBC_PRIVATE {
__sim_exceptions_thread;
__sim_disabled_exceptions_thread;
__sim_round_mode_thread;
}
}

View File

@ -23,7 +23,8 @@
int
__feclearexcept (int x)
{
__sim_exceptions &= ~x;
__sim_exceptions_thread &= ~x;
SIM_SET_GLOBAL (__sim_exceptions_global, __sim_exceptions_thread);
return 0;
}

View File

@ -24,9 +24,11 @@
int
fedisableexcept (int x)
{
int old_exceptions = ~__sim_disabled_exceptions & FE_ALL_EXCEPT;
int old_exceptions = ~__sim_disabled_exceptions_thread & FE_ALL_EXCEPT;
__sim_disabled_exceptions |= x;
__sim_disabled_exceptions_thread |= x;
SIM_SET_GLOBAL (__sim_disabled_exceptions_global,
__sim_disabled_exceptions_thread);
return old_exceptions;
}

View File

@ -17,16 +17,17 @@
License along with the GNU C Library. If not, see
<http://www.gnu.org/licenses/>. */
#include "soft-supp.h"
#include <fenv.h>
extern int __sim_disabled_exceptions;
int
feenableexcept (int exceptions)
{
int old_exceptions = ~__sim_disabled_exceptions & FE_ALL_EXCEPT;
int old_exceptions = ~__sim_disabled_exceptions_thread & FE_ALL_EXCEPT;
__sim_disabled_exceptions &= ~exceptions;
__sim_disabled_exceptions_thread &= ~exceptions;
SIM_SET_GLOBAL (__sim_disabled_exceptions_global,
__sim_disabled_exceptions_thread);
return old_exceptions;
}

View File

@ -20,18 +20,14 @@
#include "soft-fp.h"
#include "soft-supp.h"
extern int __sim_exceptions;
extern int __sim_disabled_exceptions;
extern int __sim_round_mode;
int
__fegetenv (fenv_t *envp)
{
fenv_union_t u;
u.l[0] = __sim_exceptions;
u.l[0] |= __sim_round_mode;
u.l[1] = __sim_disabled_exceptions;
u.l[0] = __sim_exceptions_thread;
u.l[0] |= __sim_round_mode_thread;
u.l[1] = __sim_disabled_exceptions_thread;
*envp = u.fenv;

View File

@ -23,5 +23,5 @@
int
fegetexcept (void)
{
return (__sim_disabled_exceptions ^ FE_ALL_EXCEPT) & FE_ALL_EXCEPT;
return (__sim_disabled_exceptions_thread ^ FE_ALL_EXCEPT) & FE_ALL_EXCEPT;
}

View File

@ -24,5 +24,5 @@
int
fegetround (void)
{
return __sim_round_mode;
return __sim_round_mode_thread;
}

View File

@ -26,9 +26,13 @@ __fesetenv (const fenv_t *envp)
fenv_union_t u;
u.fenv = *envp;
__sim_exceptions = u.l[0] & FE_ALL_EXCEPT;
__sim_round_mode = u.l[0] & 0x3;
__sim_disabled_exceptions = u.l[1];
__sim_exceptions_thread = u.l[0] & FE_ALL_EXCEPT;
SIM_SET_GLOBAL (__sim_exceptions_global, __sim_exceptions_thread);
__sim_round_mode_thread = u.l[0] & 0x3;
SIM_SET_GLOBAL (__sim_round_mode_global, __sim_round_mode_thread);
__sim_disabled_exceptions_thread = u.l[1];
SIM_SET_GLOBAL (__sim_disabled_exceptions_global,
__sim_disabled_exceptions_thread);
return 0;
}

View File

@ -26,7 +26,8 @@ fesetround (int round)
if ((unsigned int) round > FE_DOWNWARD)
return 1;
__sim_round_mode = round;
__sim_round_mode_thread = round;
SIM_SET_GLOBAL (__sim_round_mode_global, __sim_round_mode_thread);
return 0;
}

View File

@ -28,14 +28,15 @@ __feupdateenv (const fenv_t *envp)
int saved_exceptions;
/* Save currently set exceptions. */
saved_exceptions = __sim_exceptions;
saved_exceptions = __sim_exceptions_thread;
/* Set environment. */
fesetenv (envp);
/* Raise old exceptions. */
__sim_exceptions |= saved_exceptions;
if (saved_exceptions & ~__sim_disabled_exceptions)
__sim_exceptions_thread |= saved_exceptions;
SIM_SET_GLOBAL (__sim_exceptions_global, __sim_exceptions_thread);
if (saved_exceptions & ~__sim_disabled_exceptions_thread)
raise (SIGFPE);
return 0;

View File

@ -23,7 +23,7 @@
int
__fegetexceptflag (fexcept_t *flagp, int excepts)
{
*flagp = (fexcept_t) __sim_exceptions & excepts & FE_ALL_EXCEPT;
*flagp = (fexcept_t) __sim_exceptions_thread & excepts & FE_ALL_EXCEPT;
return 0;
}

View File

@ -25,8 +25,9 @@
int
__feraiseexcept (int x)
{
__sim_exceptions |= x;
if (x & ~__sim_disabled_exceptions)
__sim_exceptions_thread |= x;
SIM_SET_GLOBAL (__sim_exceptions_global, __sim_exceptions_thread);
if (x & ~__sim_disabled_exceptions_thread)
raise (SIGFPE);
return 0;
}

View File

@ -24,7 +24,9 @@ int
__fesetexceptflag(const fexcept_t *flagp, int excepts)
{
/* Ignore exceptions not listed in 'excepts'. */
__sim_exceptions = (__sim_exceptions & ~excepts) | (*flagp & excepts);
__sim_exceptions_thread
= (__sim_exceptions_thread & ~excepts) | (*flagp & excepts);
SIM_SET_GLOBAL (__sim_exceptions_global, __sim_exceptions_thread);
return 0;
}

View File

@ -23,6 +23,6 @@
int
fetestexcept (int x)
{
return __sim_exceptions & x;
return __sim_exceptions_thread & x;
}
libm_hidden_def (fetestexcept)

View File

@ -29,7 +29,7 @@
static inline int
get_rounding_mode (void)
{
return __sim_round_mode;
return __sim_round_mode_thread;
}
#endif /* get-rounding-mode.h */

View File

@ -21,26 +21,37 @@
#include "soft-fp.h"
#include "soft-supp.h"
/* FIXME: these variables should be thread specific (see bugzilla bug
15483) and ideally preserved across signal handlers, like hardware
FP status words, but the latter is quite difficult to accomplish in
userland. */
/* Global to store sticky exceptions. */
int __sim_exceptions __attribute__ ((nocommon));
libc_hidden_data_def (__sim_exceptions);
/* Thread-local to store sticky exceptions. */
__thread int __sim_exceptions_thread __attribute__ ((nocommon));
libc_hidden_data_def (__sim_exceptions_thread);
/* By default, no exceptions should trap. */
int __sim_disabled_exceptions = 0xffffffff;
libc_hidden_data_def (__sim_disabled_exceptions);
__thread int __sim_disabled_exceptions_thread = 0xffffffff;
libc_hidden_data_def (__sim_disabled_exceptions_thread);
int __sim_round_mode __attribute__ ((nocommon));
libc_hidden_data_def (__sim_round_mode);
__thread int __sim_round_mode_thread __attribute__ ((nocommon));
libc_hidden_data_def (__sim_round_mode_thread);
#if SIM_GLOBAL_COMPAT
int __sim_exceptions_global __attribute__ ((nocommon));
libc_hidden_data_def (__sim_exceptions_global);
SIM_COMPAT_SYMBOL (__sim_exceptions_global, __sim_exceptions);
int __sim_disabled_exceptions_global = 0xffffffff;
libc_hidden_data_def (__sim_disabled_exceptions_global);
SIM_COMPAT_SYMBOL (__sim_disabled_exceptions_global,
__sim_disabled_exceptions);
int __sim_round_mode_global __attribute__ ((nocommon));
libc_hidden_data_def (__sim_round_mode_global);
SIM_COMPAT_SYMBOL (__sim_round_mode_global, __sim_round_mode);
#endif
void
__simulate_exceptions (int x)
{
__sim_exceptions |= x;
if (x & ~__sim_disabled_exceptions)
__sim_exceptions_thread |= x;
SIM_SET_GLOBAL (__sim_exceptions_global, __sim_exceptions_thread);
if (x & ~__sim_disabled_exceptions_thread)
raise (SIGFPE);
}

View File

@ -33,16 +33,31 @@ typedef union
#endif
/* FIXME: these variables should be thread specific (see bugzilla bug
15483) and ideally preserved across signal handlers, like hardware
FP status words, but the latter is quite difficult to accomplish in
userland. */
extern __thread int __sim_exceptions_thread attribute_tls_model_ie;
libc_hidden_tls_proto (__sim_exceptions_thread, tls_model ("initial-exec"));
extern __thread int __sim_disabled_exceptions_thread attribute_tls_model_ie;
libc_hidden_tls_proto (__sim_disabled_exceptions_thread,
tls_model ("initial-exec"));
extern __thread int __sim_round_mode_thread attribute_tls_model_ie;
libc_hidden_tls_proto (__sim_round_mode_thread, tls_model ("initial-exec"));
extern int __sim_exceptions;
libc_hidden_proto (__sim_exceptions);
extern int __sim_disabled_exceptions;
libc_hidden_proto (__sim_disabled_exceptions);
extern int __sim_round_mode;
libc_hidden_proto (__sim_round_mode);
/* These variables were formerly global, so there are compat symbols
for global versions as well. */
#include <shlib-compat.h>
#define SIM_GLOBAL_COMPAT SHLIB_COMPAT (libc, GLIBC_2_3_2, GLIBC_2_19)
#if SIM_GLOBAL_COMPAT
extern int __sim_exceptions_global;
libc_hidden_proto (__sim_exceptions_global);
extern int __sim_disabled_exceptions_global ;
libc_hidden_proto (__sim_disabled_exceptions_global);
extern int __sim_round_mode_global;
libc_hidden_proto (__sim_round_mode_global);
# define SIM_COMPAT_SYMBOL(GLOBAL_NAME, NAME) \
compat_symbol (libc, GLOBAL_NAME, NAME, GLIBC_2_3_2)
# define SIM_SET_GLOBAL(GLOBAL_VAR, THREAD_VAR) ((GLOBAL_VAR) = (THREAD_VAR))
#else
# define SIM_SET_GLOBAL(GLOBAL_VAR, THREAD_VAR) ((void) 0)
#endif
extern void __simulate_exceptions (int x) attribute_hidden;

View File

@ -95,21 +95,18 @@ libc_hidden_proto (__feraiseexcept_soft)
# define FP_EX_INEXACT (1 << (31 - 6))
# define FP_HANDLE_EXCEPTIONS __simulate_exceptions (_fex)
# define FP_ROUNDMODE __sim_round_mode
# define FP_TRAPPING_EXCEPTIONS (~__sim_disabled_exceptions & 0x3e000000)
# define FP_ROUNDMODE __sim_round_mode_thread
# define FP_TRAPPING_EXCEPTIONS \
(~__sim_disabled_exceptions_thread & 0x3e000000)
#endif
/* FIXME: these variables should be thread specific (see bugzilla bug
15483) and ideally preserved across signal handlers, like hardware
FP status words, but the latter is quite difficult to accomplish in
userland. */
extern int __sim_exceptions;
libc_hidden_proto (__sim_exceptions);
extern int __sim_disabled_exceptions;
libc_hidden_proto (__sim_disabled_exceptions);
extern int __sim_round_mode;
libc_hidden_proto (__sim_round_mode);
extern __thread int __sim_exceptions_thread attribute_tls_model_ie;
libc_hidden_tls_proto (__sim_exceptions_thread, tls_model ("initial-exec"));
extern __thread int __sim_disabled_exceptions_thread attribute_tls_model_ie;
libc_hidden_tls_proto (__sim_disabled_exceptions_thread,
tls_model ("initial-exec"));
extern __thread int __sim_round_mode_thread attribute_tls_model_ie;
libc_hidden_tls_proto (__sim_round_mode_thread, tls_model ("initial-exec"));
extern void __simulate_exceptions (int x) attribute_hidden;