Skip to content

Commit e610387

Browse files
committed
[PAC][Driver] Support ptrauth flags only on ARM64 Darwin
Most ptrauth flags are ABI-affecting, so they should not be exposed to end users. Under certain conditions, some ptrauth driver flags are intended to be used for ARM64 Darwin, so allow them in this case. Leave `-faarch64-jump-table-hardening` available for all AArch64 targets since it's not ABI-affecting.
1 parent 5fb854a commit e610387

File tree

4 files changed

+93
-116
lines changed

4 files changed

+93
-116
lines changed

clang/lib/Driver/ToolChains/Clang.cpp

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1807,34 +1807,6 @@ void Clang::AddAArch64TargetArgs(const ArgList &Args,
18071807

18081808
AddUnalignedAccessWarning(CmdArgs);
18091809

1810-
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_intrinsics,
1811-
options::OPT_fno_ptrauth_intrinsics);
1812-
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_calls,
1813-
options::OPT_fno_ptrauth_calls);
1814-
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_returns,
1815-
options::OPT_fno_ptrauth_returns);
1816-
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_auth_traps,
1817-
options::OPT_fno_ptrauth_auth_traps);
1818-
Args.addOptInFlag(
1819-
CmdArgs, options::OPT_fptrauth_vtable_pointer_address_discrimination,
1820-
options::OPT_fno_ptrauth_vtable_pointer_address_discrimination);
1821-
Args.addOptInFlag(
1822-
CmdArgs, options::OPT_fptrauth_vtable_pointer_type_discrimination,
1823-
options::OPT_fno_ptrauth_vtable_pointer_type_discrimination);
1824-
Args.addOptInFlag(
1825-
CmdArgs, options::OPT_fptrauth_type_info_vtable_pointer_discrimination,
1826-
options::OPT_fno_ptrauth_type_info_vtable_pointer_discrimination);
1827-
Args.addOptInFlag(
1828-
CmdArgs, options::OPT_fptrauth_function_pointer_type_discrimination,
1829-
options::OPT_fno_ptrauth_function_pointer_type_discrimination);
1830-
1831-
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_indirect_gotos,
1832-
options::OPT_fno_ptrauth_indirect_gotos);
1833-
Args.addOptInFlag(CmdArgs, options::OPT_fptrauth_init_fini,
1834-
options::OPT_fno_ptrauth_init_fini);
1835-
Args.addOptInFlag(CmdArgs,
1836-
options::OPT_fptrauth_init_fini_address_discrimination,
1837-
options::OPT_fno_ptrauth_init_fini_address_discrimination);
18381810
Args.addOptInFlag(CmdArgs, options::OPT_faarch64_jump_table_hardening,
18391811
options::OPT_fno_aarch64_jump_table_hardening);
18401812
}

clang/lib/Driver/ToolChains/Darwin.cpp

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3061,6 +3061,40 @@ bool Darwin::isSizedDeallocationUnavailable() const {
30613061
return TargetVersion < sizedDeallocMinVersion(OS);
30623062
}
30633063

3064+
static void addPointerAuthFlags(const llvm::opt::ArgList &DriverArgs,
3065+
llvm::opt::ArgStringList &CC1Args) {
3066+
DriverArgs.addOptInFlag(CC1Args, options::OPT_fptrauth_intrinsics,
3067+
options::OPT_fno_ptrauth_intrinsics);
3068+
3069+
DriverArgs.addOptInFlag(CC1Args, options::OPT_fptrauth_calls,
3070+
options::OPT_fno_ptrauth_calls);
3071+
3072+
DriverArgs.addOptInFlag(CC1Args, options::OPT_fptrauth_returns,
3073+
options::OPT_fno_ptrauth_returns);
3074+
3075+
DriverArgs.addOptInFlag(CC1Args, options::OPT_fptrauth_auth_traps,
3076+
options::OPT_fno_ptrauth_auth_traps);
3077+
3078+
DriverArgs.addOptInFlag(
3079+
CC1Args, options::OPT_fptrauth_vtable_pointer_address_discrimination,
3080+
options::OPT_fno_ptrauth_vtable_pointer_address_discrimination);
3081+
3082+
DriverArgs.addOptInFlag(
3083+
CC1Args, options::OPT_fptrauth_vtable_pointer_type_discrimination,
3084+
options::OPT_fno_ptrauth_vtable_pointer_type_discrimination);
3085+
3086+
DriverArgs.addOptInFlag(
3087+
CC1Args, options::OPT_fptrauth_type_info_vtable_pointer_discrimination,
3088+
options::OPT_fno_ptrauth_type_info_vtable_pointer_discrimination);
3089+
3090+
DriverArgs.addOptInFlag(
3091+
CC1Args, options::OPT_fptrauth_function_pointer_type_discrimination,
3092+
options::OPT_fno_ptrauth_function_pointer_type_discrimination);
3093+
3094+
DriverArgs.addOptInFlag(CC1Args, options::OPT_fptrauth_indirect_gotos,
3095+
options::OPT_fno_ptrauth_indirect_gotos);
3096+
}
3097+
30643098
void Darwin::addClangTargetOptions(
30653099
const llvm::opt::ArgList &DriverArgs, llvm::opt::ArgStringList &CC1Args,
30663100
Action::OffloadKind DeviceOffloadKind) const {
@@ -3137,6 +3171,9 @@ void Darwin::addClangTargetOptions(
31373171
if (!RequiresSubdirectorySearch)
31383172
CC1Args.push_back("-fno-modulemap-allow-subdirectory-search");
31393173
}
3174+
3175+
if (getTriple().isAArch64())
3176+
addPointerAuthFlags(DriverArgs, CC1Args);
31403177
}
31413178

31423179
void Darwin::addClangCC1ASTargetOptions(

clang/lib/Driver/ToolChains/Linux.cpp

Lines changed: 10 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -476,49 +476,16 @@ std::string Linux::ComputeEffectiveClangTriple(const llvm::opt::ArgList &Args,
476476
// options represent the default signing schema.
477477
static void handlePAuthABI(const Driver &D, const ArgList &DriverArgs,
478478
ArgStringList &CC1Args) {
479-
if (!DriverArgs.hasArg(options::OPT_fptrauth_intrinsics,
480-
options::OPT_fno_ptrauth_intrinsics))
481-
CC1Args.push_back("-fptrauth-intrinsics");
482-
483-
if (!DriverArgs.hasArg(options::OPT_fptrauth_calls,
484-
options::OPT_fno_ptrauth_calls))
485-
CC1Args.push_back("-fptrauth-calls");
486-
487-
if (!DriverArgs.hasArg(options::OPT_fptrauth_returns,
488-
options::OPT_fno_ptrauth_returns))
489-
CC1Args.push_back("-fptrauth-returns");
490-
491-
if (!DriverArgs.hasArg(options::OPT_fptrauth_auth_traps,
492-
options::OPT_fno_ptrauth_auth_traps))
493-
CC1Args.push_back("-fptrauth-auth-traps");
494-
495-
if (!DriverArgs.hasArg(
496-
options::OPT_fptrauth_vtable_pointer_address_discrimination,
497-
options::OPT_fno_ptrauth_vtable_pointer_address_discrimination))
498-
CC1Args.push_back("-fptrauth-vtable-pointer-address-discrimination");
499-
500-
if (!DriverArgs.hasArg(
501-
options::OPT_fptrauth_vtable_pointer_type_discrimination,
502-
options::OPT_fno_ptrauth_vtable_pointer_type_discrimination))
503-
CC1Args.push_back("-fptrauth-vtable-pointer-type-discrimination");
504-
505-
if (!DriverArgs.hasArg(
506-
options::OPT_fptrauth_type_info_vtable_pointer_discrimination,
507-
options::OPT_fno_ptrauth_type_info_vtable_pointer_discrimination))
508-
CC1Args.push_back("-fptrauth-type-info-vtable-pointer-discrimination");
509-
510-
if (!DriverArgs.hasArg(options::OPT_fptrauth_indirect_gotos,
511-
options::OPT_fno_ptrauth_indirect_gotos))
512-
CC1Args.push_back("-fptrauth-indirect-gotos");
513-
514-
if (!DriverArgs.hasArg(options::OPT_fptrauth_init_fini,
515-
options::OPT_fno_ptrauth_init_fini))
516-
CC1Args.push_back("-fptrauth-init-fini");
517-
518-
if (!DriverArgs.hasArg(
519-
options::OPT_fptrauth_init_fini_address_discrimination,
520-
options::OPT_fno_ptrauth_init_fini_address_discrimination))
521-
CC1Args.push_back("-fptrauth-init-fini-address-discrimination");
479+
CC1Args.push_back("-fptrauth-intrinsics");
480+
CC1Args.push_back("-fptrauth-calls");
481+
CC1Args.push_back("-fptrauth-returns");
482+
CC1Args.push_back("-fptrauth-auth-traps");
483+
CC1Args.push_back("-fptrauth-vtable-pointer-address-discrimination");
484+
CC1Args.push_back("-fptrauth-vtable-pointer-type-discrimination");
485+
CC1Args.push_back("-fptrauth-type-info-vtable-pointer-discrimination");
486+
CC1Args.push_back("-fptrauth-indirect-gotos");
487+
CC1Args.push_back("-fptrauth-init-fini");
488+
CC1Args.push_back("-fptrauth-init-fini-address-discrimination");
522489

523490
if (!DriverArgs.hasArg(options::OPT_faarch64_jump_table_hardening,
524491
options::OPT_fno_aarch64_jump_table_hardening))

clang/test/Driver/aarch64-ptrauth.c

Lines changed: 46 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,12 @@
44
// NONE: "-cc1"
55
// NONE-NOT: "-fptrauth-
66

7-
// RUN: %clang -### -c --target=aarch64 \
7+
// RUN: %clang -### -c --target=aarch64-linux \
8+
// RUN: -fno-aarch64-jump-table-hardening -faarch64-jump-table-hardening \
9+
// RUN: %s 2>&1 | FileCheck %s --check-prefix=ALL-LINUX
10+
// ALL-LINUX: "-cc1"{{.*}} "-faarch64-jump-table-hardening"
11+
12+
// RUN: %clang -### -c --target=arm64-darwin \
813
// RUN: -fno-ptrauth-intrinsics -fptrauth-intrinsics \
914
// RUN: -fno-ptrauth-calls -fptrauth-calls \
1015
// RUN: -fno-ptrauth-returns -fptrauth-returns \
@@ -13,11 +18,9 @@
1318
// RUN: -fno-ptrauth-vtable-pointer-type-discrimination -fptrauth-vtable-pointer-type-discrimination \
1419
// RUN: -fno-ptrauth-type-info-vtable-pointer-discrimination -fptrauth-type-info-vtable-pointer-discrimination \
1520
// RUN: -fno-ptrauth-indirect-gotos -fptrauth-indirect-gotos \
16-
// RUN: -fno-ptrauth-init-fini -fptrauth-init-fini \
17-
// RUN: -fno-ptrauth-init-fini-address-discrimination -fptrauth-init-fini-address-discrimination \
1821
// RUN: -fno-aarch64-jump-table-hardening -faarch64-jump-table-hardening \
19-
// RUN: %s 2>&1 | FileCheck %s --check-prefix=ALL
20-
// ALL: "-cc1"{{.*}} "-fptrauth-intrinsics" "-fptrauth-calls" "-fptrauth-returns" "-fptrauth-auth-traps" "-fptrauth-vtable-pointer-address-discrimination" "-fptrauth-vtable-pointer-type-discrimination" "-fptrauth-type-info-vtable-pointer-discrimination" "-fptrauth-indirect-gotos" "-fptrauth-init-fini" "-fptrauth-init-fini-address-discrimination" "-faarch64-jump-table-hardening"
22+
// RUN: %s 2>&1 | FileCheck %s --check-prefix=ALL-DARWIN
23+
// ALL-DARWIN: "-cc1"{{.*}} "-fptrauth-intrinsics" "-fptrauth-calls" "-fptrauth-returns" "-fptrauth-auth-traps" "-fptrauth-vtable-pointer-address-discrimination" "-fptrauth-vtable-pointer-type-discrimination" "-fptrauth-type-info-vtable-pointer-discrimination" "-fptrauth-indirect-gotos"{{.*}} "-faarch64-jump-table-hardening"
2124

2225
// RUN: %clang -### -c --target=aarch64-linux -mabi=pauthtest %s 2>&1 | FileCheck %s --check-prefix=PAUTHABI1
2326
// RUN: %clang -### -c --target=aarch64-linux-pauthtest %s 2>&1 | FileCheck %s --check-prefix=PAUTHABI1
@@ -26,36 +29,34 @@
2629
// PAUTHABI1-SAME: "-target-abi" "pauthtest"
2730
// PAUTHABI1-NOT: "-fptrauth-function-pointer-type-discrimination"
2831

29-
// RUN: %clang -### -c --target=aarch64-linux -mabi=pauthtest -fno-ptrauth-intrinsics \
30-
// RUN: -fno-ptrauth-calls -fno-ptrauth-returns -fno-ptrauth-auth-traps \
31-
// RUN: -fno-ptrauth-vtable-pointer-address-discrimination -fno-ptrauth-vtable-pointer-type-discrimination \
32-
// RUN: -fno-ptrauth-type-info-vtable-pointer-discrimination -fno-ptrauth-indirect-gotos \
33-
// RUN: -fno-ptrauth-init-fini -fno-ptrauth-init-fini-address-discrimination \
32+
// RUN: %clang -### -c --target=aarch64-linux -mabi=pauthtest \
3433
// RUN: -fno-aarch64-jump-table-hardening %s 2>&1 | FileCheck %s --check-prefix=PAUTHABI2
35-
// RUN: %clang -### -c --target=aarch64-linux-pauthtest -fno-ptrauth-intrinsics \
36-
// RUN: -fno-ptrauth-calls -fno-ptrauth-returns -fno-ptrauth-auth-traps \
37-
// RUN: -fno-ptrauth-vtable-pointer-address-discrimination -fno-ptrauth-vtable-pointer-type-discrimination \
38-
// RUN: -fno-ptrauth-type-info-vtable-pointer-discrimination -fno-ptrauth-indirect-gotos \
39-
// RUN: -fno-ptrauth-init-fini -fno-ptrauth-init-fini-address-discrimination \
34+
// RUN: %clang -### -c --target=aarch64-linux-pauthtest \
4035
// RUN: -fno-aarch64-jump-table-hardening %s 2>&1 | FileCheck %s --check-prefix=PAUTHABI2
4136

4237
//// Non-linux OS: pauthtest ABI has no effect in terms of passing ptrauth cc1 flags.
43-
//// An error about unsupported ABI will be emitted later in pipeline (see ERR2 below)
44-
// RUN: %clang -### -c --target=aarch64 -mabi=pauthtest %s 2>&1 | FileCheck %s --check-prefix=PAUTHABI2
38+
//// An error about unsupported ABI will be emitted later in pipeline (see ERR3 below)
39+
// RUN: %clang -### -c --target=aarch64 -mabi=pauthtest %s 2>&1 | FileCheck %s --check-prefixes=PAUTHABI2,PAUTHABI3
4540

4641
// PAUTHABI2: "-cc1"
4742
// PAUTHABI2-SAME: "-target-abi" "pauthtest"
48-
// PAUTHABI2-NOT: "-fptrauth-
43+
// PAUTHABI3-NOT: "-fptrauth-
4944
// PAUTHABI2-NOT: "-faarch64-jump-table-hardening"
5045

5146
//// Non-linux OS: pauthtest environment does not correspond to pauthtest ABI; aapcs is the default.
52-
// RUN: %clang -### -c --target=aarch64-pauthtest %s 2>&1 | FileCheck %s --check-prefix=PAUTHABI3
53-
// PAUTHABI3: "-cc1"
54-
// PAUTHABI3-SAME: "-target-abi" "aapcs"
55-
// PAUTHABI3-NOT: "-fptrauth-
56-
// PAUTHABI3-NOT: "-faarch64-jump-table-hardening"
57-
58-
// RUN: not %clang -### -c --target=x86_64 -fptrauth-intrinsics -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps \
47+
// RUN: %clang -### -c --target=aarch64-pauthtest %s 2>&1 | FileCheck %s --check-prefix=PAUTHABI4
48+
// PAUTHABI4: "-cc1"
49+
// PAUTHABI4-SAME: "-target-abi" "aapcs"
50+
// PAUTHABI4-NOT: "-fptrauth-
51+
// PAUTHABI4-NOT: "-faarch64-jump-table-hardening"
52+
53+
//// Non-AArch64.
54+
// RUN: not %clang -### -c --target=x86_64-linux -fptrauth-intrinsics -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps \
55+
// RUN: -fptrauth-vtable-pointer-address-discrimination -fptrauth-vtable-pointer-type-discrimination \
56+
// RUN: -fptrauth-type-info-vtable-pointer-discrimination -fptrauth-indirect-gotos -fptrauth-init-fini \
57+
// RUN: -fptrauth-init-fini-address-discrimination -faarch64-jump-table-hardening %s 2>&1 | FileCheck %s --check-prefixes=ERR1,ERR2
58+
//// Non-linux and non-Darwin OS.
59+
// RUN: not %clang -### -c --target=aarch64 -fptrauth-intrinsics -fptrauth-calls -fptrauth-returns -fptrauth-auth-traps \
5960
// RUN: -fptrauth-vtable-pointer-address-discrimination -fptrauth-vtable-pointer-type-discrimination \
6061
// RUN: -fptrauth-type-info-vtable-pointer-discrimination -fptrauth-indirect-gotos -fptrauth-init-fini \
6162
// RUN: -fptrauth-init-fini-address-discrimination -faarch64-jump-table-hardening %s 2>&1 | FileCheck %s --check-prefix=ERR1
@@ -69,50 +70,50 @@
6970
// ERR1-NEXT: error: unsupported option '-fptrauth-indirect-gotos' for target '{{.*}}'
7071
// ERR1-NEXT: error: unsupported option '-fptrauth-init-fini' for target '{{.*}}'
7172
// ERR1-NEXT: error: unsupported option '-fptrauth-init-fini-address-discrimination' for target '{{.*}}'
72-
// ERR1-NEXT: error: unsupported option '-faarch64-jump-table-hardening' for target '{{.*}}'
73+
// ERR2-NEXT: error: unsupported option '-faarch64-jump-table-hardening' for target '{{.*}}'
7374

7475

75-
// RUN: not %clang -c --target=aarch64 -mabi=pauthtest %s 2>&1 | FileCheck %s --check-prefix=ERR2
76+
// RUN: not %clang -c --target=aarch64 -mabi=pauthtest %s 2>&1 | FileCheck %s --check-prefix=ERR3
7677
//// The ABI is not specified explicitly, and for non-Linux pauthtest environment does not correspond
7778
//// to pauthtest ABI (each OS target defines this behavior separately). Do not emit an error.
7879
// RUN: %clang -c --target=aarch64-pauthtest %s -o /dev/null
79-
// ERR2: error: unknown target ABI 'pauthtest'
80+
// ERR3: error: unknown target ABI 'pauthtest'
8081

8182
//// PAuth ABI is encoded as environment part of the triple, so don't allow to explicitly set other environments.
82-
// RUN: not %clang -### -c --target=aarch64-linux-gnu -mabi=pauthtest %s 2>&1 | FileCheck %s --check-prefix=ERR3
83-
// ERR3: error: unsupported option '-mabi=pauthtest' for target 'aarch64-unknown-linux-gnu'
83+
// RUN: not %clang -### -c --target=aarch64-linux-gnu -mabi=pauthtest %s 2>&1 | FileCheck %s --check-prefix=ERR4
84+
// ERR4: error: unsupported option '-mabi=pauthtest' for target 'aarch64-unknown-linux-gnu'
8485
// RUN: %clang -### -c --target=aarch64-linux-pauthtest -mabi=pauthtest %s
8586

8687
//// The only branch protection option compatible with PAuthABI is BTI.
8788
// RUN: not %clang -### -c --target=aarch64-linux -mabi=pauthtest -mbranch-protection=pac-ret %s 2>&1 | \
88-
// RUN: FileCheck %s --check-prefix=ERR4
89+
// RUN: FileCheck %s --check-prefix=ERR5
8990
// RUN: not %clang -### -c --target=aarch64-linux-pauthtest -mbranch-protection=pac-ret %s 2>&1 | \
90-
// RUN: FileCheck %s --check-prefix=ERR4
91-
// ERR4: error: unsupported option '-mbranch-protection=pac-ret' for target 'aarch64-unknown-linux-pauthtest'
91+
// RUN: FileCheck %s --check-prefix=ERR5
92+
// ERR5: error: unsupported option '-mbranch-protection=pac-ret' for target 'aarch64-unknown-linux-pauthtest'
9293

9394
// RUN: not %clang -### -c --target=aarch64-linux -mabi=pauthtest -mbranch-protection=gcs %s 2>&1 | \
94-
// RUN: FileCheck %s --check-prefix=ERR5
95+
// RUN: FileCheck %s --check-prefix=ERR6
9596
// RUN: not %clang -### -c --target=aarch64-linux-pauthtest -mbranch-protection=gcs %s 2>&1 | \
96-
// RUN: FileCheck %s --check-prefix=ERR5
97-
// ERR5: error: unsupported option '-mbranch-protection=gcs' for target 'aarch64-unknown-linux-pauthtest'
97+
// RUN: FileCheck %s --check-prefix=ERR6
98+
// ERR6: error: unsupported option '-mbranch-protection=gcs' for target 'aarch64-unknown-linux-pauthtest'
9899

99100
// RUN: not %clang -### -c --target=aarch64-linux -mabi=pauthtest -mbranch-protection=standard %s 2>&1 | \
100-
// RUN: FileCheck %s --check-prefix=ERR6
101+
// RUN: FileCheck %s --check-prefix=ERR7
101102
// RUN: not %clang -### -c --target=aarch64-linux-pauthtest -mbranch-protection=standard %s 2>&1 | \
102-
// RUN: FileCheck %s --check-prefix=ERR6
103-
// ERR6: error: unsupported option '-mbranch-protection=standard' for target 'aarch64-unknown-linux-pauthtest'
103+
// RUN: FileCheck %s --check-prefix=ERR7
104+
// ERR7: error: unsupported option '-mbranch-protection=standard' for target 'aarch64-unknown-linux-pauthtest'
104105

105106
// RUN: not %clang -### -c --target=aarch64-linux -mabi=pauthtest -msign-return-address=all %s 2>&1 | \
106-
// RUN: FileCheck %s --check-prefix=ERR7
107+
// RUN: FileCheck %s --check-prefix=ERR8
107108
// RUN: not %clang -### -c --target=aarch64-linux-pauthtest -msign-return-address=all %s 2>&1 | \
108-
// RUN: FileCheck %s --check-prefix=ERR7
109-
// ERR7: error: unsupported option '-msign-return-address=all' for target 'aarch64-unknown-linux-pauthtest'
109+
// RUN: FileCheck %s --check-prefix=ERR8
110+
// ERR8: error: unsupported option '-msign-return-address=all' for target 'aarch64-unknown-linux-pauthtest'
110111

111112
// RUN: not %clang -### -c --target=aarch64-linux -mabi=pauthtest -msign-return-address=non-leaf %s 2>&1 | \
112-
// RUN: FileCheck %s --check-prefix=ERR8
113+
// RUN: FileCheck %s --check-prefix=ERR9
113114
// RUN: not %clang -### -c --target=aarch64-linux-pauthtest -msign-return-address=non-leaf %s 2>&1 | \
114-
// RUN: FileCheck %s --check-prefix=ERR8
115-
// ERR8: error: unsupported option '-msign-return-address=non-leaf' for target 'aarch64-unknown-linux-pauthtest'
115+
// RUN: FileCheck %s --check-prefix=ERR9
116+
// ERR9: error: unsupported option '-msign-return-address=non-leaf' for target 'aarch64-unknown-linux-pauthtest'
116117

117118
// RUN: %clang -### -c --target=aarch64-linux -mabi=pauthtest -msign-return-address=none %s
118119
// RUN: %clang -### -c --target=aarch64-linux-pauthtest -msign-return-address=none %s

0 commit comments

Comments
 (0)