Filename | /usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf/Parser.pm |
Statements | Executed 1032701 statements in 8.48s |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
13832 | 2 | 1 | 4.00s | 5.46s | _meta_deps_recurse (recurses: max depth 7, inclusive time 11.0s) | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 1.56s | 4.68s | parse | Mail::SpamAssassin::Conf::Parser::
322611 | 28 | 1 | 1.24s | 1.24s | CORE:match (opcode) | Mail::SpamAssassin::Conf::Parser::
92819 | 21 | 1 | 265ms | 265ms | CORE:subst (opcode) | Mail::SpamAssassin::Conf::Parser::
2074 | 15 | 3 | 207ms | 726ms | add_test | Mail::SpamAssassin::Conf::Parser::
465 | 1 | 1 | 169ms | 222ms | is_meta_valid | Mail::SpamAssassin::Conf::Parser::
508 | 2 | 1 | 142ms | 211ms | handle_conditional | Mail::SpamAssassin::Conf::Parser::
15046 | 6 | 1 | 137ms | 137ms | CORE:regcomp (opcode) | Mail::SpamAssassin::Conf::Parser::
1228 | 1 | 1 | 123ms | 231ms | is_regexp_valid | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 119ms | 123ms | set_default_scores | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 112ms | 116ms | find_dup_rules | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 104ms | 6.01s | finish_parsing | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 91.0ms | 111ms | fix_priorities | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 63.0ms | 154ms | check_for_missing_descriptions | Mail::SpamAssassin::Conf::Parser::
1276 | 1 | 1 | 57.2ms | 260ms | set_hash_key_value | Mail::SpamAssassin::Conf::Parser::
1228 | 4 | 3 | 46.2ms | 285ms | is_delimited_regexp_valid | Mail::SpamAssassin::Conf::Parser::
379 | 1 | 1 | 39.4ms | 47.1ms | pack_eval_method | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 31.3ms | 5.49s | trace_meta_dependencies | Mail::SpamAssassin::Conf::Parser::
11 | 2 | 1 | 20.1ms | 20.1ms | CORE:sort (opcode) | Mail::SpamAssassin::Conf::Parser::
102 | 2 | 2 | 7.71ms | 10.4ms | add_to_addrlist_rcvd | Mail::SpamAssassin::Conf::Parser::
58 | 1 | 1 | 4.67ms | 23.2ms | fix_path_relative_to_current_file | Mail::SpamAssassin::Conf::Parser::
16 | 1 | 1 | 4.09ms | 4.09ms | build_command_luts | Mail::SpamAssassin::Conf::Parser::
434 | 43 | 43 | 3.99ms | 3.99ms | cond_clause_plugin_loaded | Mail::SpamAssassin::Conf::Parser::
34 | 1 | 1 | 2.73ms | 3.63ms | add_to_addrlist | Mail::SpamAssassin::Conf::Parser::
55 | 1 | 1 | 2.63ms | 4.20ms | cond_clause_can_or_has | Mail::SpamAssassin::Conf::Parser::
16 | 1 | 1 | 2.16ms | 2.16ms | set_defaults_from_command_list | Mail::SpamAssassin::Conf::Parser::
479 | 2 | 1 | 1.67ms | 1.67ms | CORE:substcont (opcode) | Mail::SpamAssassin::Conf::Parser::
83 | 1 | 1 | 980µs | 9.26ms | add_to_addrlist_dkim | Mail::SpamAssassin::Conf::Parser::
55 | 14 | 14 | 942µs | 5.14ms | cond_clause_can | Mail::SpamAssassin::Conf::Parser::
34 | 1 | 1 | 885µs | 4.60ms | set_addrlist_value | Mail::SpamAssassin::Conf::Parser::
16 | 16 | 16 | 842µs | 7.09ms | register_commands | Mail::SpamAssassin::Conf::Parser::
21 | 1 | 1 | 510µs | 510µs | setup_default_code_cb | Mail::SpamAssassin::Conf::Parser::
17 | 1 | 1 | 494µs | 542µs | set_template_append | Mail::SpamAssassin::Conf::Parser::
5 | 1 | 1 | 242µs | 255µs | set_bool_value | Mail::SpamAssassin::Conf::Parser::
4 | 1 | 1 | 209µs | 394µs | set_numeric_value | Mail::SpamAssassin::Conf::Parser::
3 | 1 | 1 | 78µs | 94µs | set_string_value | Mail::SpamAssassin::Conf::Parser::
2 | 1 | 1 | 52µs | 52µs | set_template_clear | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 49µs | 49µs | BEGIN@137 | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 37µs | 95µs | BEGIN@592 | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 30µs | 30µs | new | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 28µs | 38µs | BEGIN@143 | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 27µs | 377µs | BEGIN@140 | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 23µs | 229µs | BEGIN@139 | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 22µs | 29µs | BEGIN@145 | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 21µs | 90µs | BEGIN@146 | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 20µs | 57µs | BEGIN@144 | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 20µs | 20µs | lint_trusted_networks | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 20µs | 88µs | BEGIN@148 | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 19µs | 719µs | BEGIN@138 | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 14µs | 14µs | BEGIN@141 | Mail::SpamAssassin::Conf::Parser::
1 | 1 | 1 | 13µs | 13µs | lint_check | Mail::SpamAssassin::Conf::Parser::
0 | 0 | 0 | 0s | 0s | add_regression_test | Mail::SpamAssassin::Conf::Parser::
0 | 0 | 0 | 0s | 0s | cond_clause_has | Mail::SpamAssassin::Conf::Parser::
0 | 0 | 0 | 0s | 0s | get_if_stack_as_string | Mail::SpamAssassin::Conf::Parser::
0 | 0 | 0 | 0s | 0s | is_always_matching_regexp | Mail::SpamAssassin::Conf::Parser::
0 | 0 | 0 | 0s | 0s | lint_warn | Mail::SpamAssassin::Conf::Parser::
0 | 0 | 0 | 0s | 0s | remove_addrlist_value | Mail::SpamAssassin::Conf::Parser::
0 | 0 | 0 | 0s | 0s | remove_from_addrlist | Mail::SpamAssassin::Conf::Parser::
0 | 0 | 0 | 0s | 0s | remove_from_addrlist_dkim | Mail::SpamAssassin::Conf::Parser::
0 | 0 | 0 | 0s | 0s | remove_from_addrlist_rcvd | Mail::SpamAssassin::Conf::Parser::
0 | 0 | 0 | 0s | 0s | set_duration_value | Mail::SpamAssassin::Conf::Parser::
0 | 0 | 0 | 0s | 0s | set_ipaddr_list | Mail::SpamAssassin::Conf::Parser::
0 | 0 | 0 | 0s | 0s | set_no_value | Mail::SpamAssassin::Conf::Parser::
0 | 0 | 0 | 0s | 0s | set_string_list | Mail::SpamAssassin::Conf::Parser::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | # <@LICENSE> | ||||
2 | # Licensed to the Apache Software Foundation (ASF) under one or more | ||||
3 | # contributor license agreements. See the NOTICE file distributed with | ||||
4 | # this work for additional information regarding copyright ownership. | ||||
5 | # The ASF licenses this file to you under the Apache License, Version 2.0 | ||||
6 | # (the "License"); you may not use this file except in compliance with | ||||
7 | # the License. You may obtain a copy of the License at: | ||||
8 | # | ||||
9 | # http://www.apache.org/licenses/LICENSE-2.0 | ||||
10 | # | ||||
11 | # Unless required by applicable law or agreed to in writing, software | ||||
12 | # distributed under the License is distributed on an "AS IS" BASIS, | ||||
13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
14 | # See the License for the specific language governing permissions and | ||||
15 | # limitations under the License. | ||||
16 | # </@LICENSE> | ||||
17 | |||||
18 | =head1 NAME | ||||
19 | |||||
20 | Mail::SpamAssassin::Conf::Parser - parse SpamAssassin configuration | ||||
21 | |||||
22 | =head1 SYNOPSIS | ||||
23 | |||||
24 | (see Mail::SpamAssassin) | ||||
25 | |||||
26 | =head1 DESCRIPTION | ||||
27 | |||||
28 | Mail::SpamAssassin is a module to identify spam using text analysis and | ||||
29 | several internet-based realtime blacklists. | ||||
30 | |||||
31 | This class is used internally by SpamAssassin to parse its configuration files. | ||||
32 | Please refer to the C<Mail::SpamAssassin> documentation for public interfaces. | ||||
33 | |||||
34 | =head1 STRUCTURE OF A CONFIG BLOCK | ||||
35 | |||||
36 | This is the structure of a config-setting block. Each is a hashref which may | ||||
37 | contain these keys: | ||||
38 | |||||
39 | =over 4 | ||||
40 | |||||
41 | =item setting | ||||
42 | |||||
43 | the name of the setting it modifies, e.g. "required_score". this also doubles | ||||
44 | as the default for 'command' (below). THIS IS REQUIRED. | ||||
45 | |||||
46 | =item command | ||||
47 | |||||
48 | The command string used in the config file for this setting. Optional; | ||||
49 | 'setting' will be used for the command if this is omitted. | ||||
50 | |||||
51 | =item aliases | ||||
52 | |||||
53 | An [aryref] of other aliases for the same command. optional. | ||||
54 | |||||
55 | =item type | ||||
56 | |||||
57 | The type of this setting: | ||||
58 | |||||
59 | - $CONF_TYPE_NOARGS: must not have any argument, like "clear_headers" | ||||
60 | - $CONF_TYPE_STRING: string | ||||
61 | - $CONF_TYPE_NUMERIC: numeric value (float or int) | ||||
62 | - $CONF_TYPE_BOOL: boolean (0/no or 1/yes) | ||||
63 | - $CONF_TYPE_TEMPLATE: template, like "report" | ||||
64 | - $CONF_TYPE_ADDRLIST: list of mail addresses, like "whitelist_from" | ||||
65 | - $CONF_TYPE_HASH_KEY_VALUE: hash key/value pair, like "describe" or tflags | ||||
66 | - $CONF_TYPE_STRINGLIST list of strings, stored as an array | ||||
67 | - $CONF_TYPE_IPADDRLIST list of IP addresses, stored as an array of SA::NetSet | ||||
68 | - $CONF_TYPE_DURATION a nonnegative time interval in seconds - a numeric value | ||||
69 | (float or int), optionally suffixed by a time unit (s, m, | ||||
70 | h, d, w), seconds are implied if unit is missing | ||||
71 | |||||
72 | If this is set, and a 'code' block does not already exist, a 'code' block is | ||||
73 | assigned based on the type. | ||||
74 | |||||
75 | In addition, the SpamAssassin test suite will validate that the settings | ||||
76 | do not 'leak' between users. | ||||
77 | |||||
78 | Note that C<$CONF_TYPE_HASH_KEY_VALUE>-type settings require that the | ||||
79 | value be non-empty, otherwise they'll produce a warning message. | ||||
80 | |||||
81 | =item code | ||||
82 | |||||
83 | A subroutine to deal with the setting. ONE OF B<code> OR B<type> IS REQUIRED. | ||||
84 | The arguments passed to the function are C<($self, $key, $value, $line)>, | ||||
85 | where $key is the setting (*not* the command), $value is the value string, | ||||
86 | and $line is the entire line. | ||||
87 | |||||
88 | There are two special return values that the B<code> subroutine may return | ||||
89 | to signal that there is an error in the configuration: | ||||
90 | |||||
91 | C<$Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE> -- this setting requires | ||||
92 | that a value be set, but one was not provided. | ||||
93 | |||||
94 | C<$Mail::SpamAssassin::Conf::INVALID_VALUE> -- this setting requires a value | ||||
95 | from a set of 'valid' values, but the user provided an invalid one. | ||||
96 | |||||
97 | C<$Mail::SpamAssassin::Conf::INVALID_HEADER_FIELD_NAME> -- this setting | ||||
98 | requires a syntactically valid header field name, but the user provided | ||||
99 | an invalid one. | ||||
100 | |||||
101 | Any other values -- including C<undef> -- returned from the subroutine are | ||||
102 | considered to mean 'success'. | ||||
103 | |||||
104 | It is good practice to set a 'type', if possible, describing how your settings | ||||
105 | are stored on the Conf object; this allows the SpamAssassin test suite to | ||||
106 | validate that the settings do not 'leak' between users. | ||||
107 | |||||
108 | =item default | ||||
109 | |||||
110 | The default value for the setting. may be omitted if the default value is a | ||||
111 | non-scalar type, which should be set in the Conf ctor. note for path types: | ||||
112 | using "__userstate__" is recommended for defaults, as it allows | ||||
113 | Mail::SpamAssassin module users who set that configuration setting, to receive | ||||
114 | the correct values. | ||||
115 | |||||
116 | =item is_priv | ||||
117 | |||||
118 | Set to 1 if this setting requires 'allow_user_rules' when run from spamd. | ||||
119 | |||||
120 | =item is_admin | ||||
121 | |||||
122 | Set to 1 if this setting can only be set in the system-wide config when run | ||||
123 | from spamd. (All settings can be used by local programs run directly by the | ||||
124 | user.) | ||||
125 | |||||
126 | =item is_frequent | ||||
127 | |||||
128 | Set to 1 if this value occurs frequently in the config. this means it's looked | ||||
129 | up first for speed. | ||||
130 | |||||
131 | =back | ||||
132 | |||||
133 | =cut | ||||
134 | |||||
135 | package Mail::SpamAssassin::Conf::Parser; | ||||
136 | |||||
137 | 2 | 79µs | 1 | 49µs | # spent 49µs within Mail::SpamAssassin::Conf::Parser::BEGIN@137 which was called:
# once (49µs+0s) by Mail::SpamAssassin::Conf::BEGIN@88 at line 137 # spent 49µs making 1 call to Mail::SpamAssassin::Conf::Parser::BEGIN@137 |
138 | 2 | 72µs | 2 | 1.42ms | # spent 719µs (19+700) within Mail::SpamAssassin::Conf::Parser::BEGIN@138 which was called:
# once (19µs+700µs) by Mail::SpamAssassin::Conf::BEGIN@88 at line 138 # spent 719µs making 1 call to Mail::SpamAssassin::Conf::Parser::BEGIN@138
# spent 700µs making 1 call to Exporter::import |
139 | 2 | 75µs | 2 | 435µs | # spent 229µs (23+206) within Mail::SpamAssassin::Conf::Parser::BEGIN@139 which was called:
# once (23µs+206µs) by Mail::SpamAssassin::Conf::BEGIN@88 at line 139 # spent 229µs making 1 call to Mail::SpamAssassin::Conf::Parser::BEGIN@139
# spent 206µs making 1 call to Exporter::import |
140 | 2 | 75µs | 2 | 727µs | # spent 377µs (27+350) within Mail::SpamAssassin::Conf::Parser::BEGIN@140 which was called:
# once (27µs+350µs) by Mail::SpamAssassin::Conf::BEGIN@88 at line 140 # spent 377µs making 1 call to Mail::SpamAssassin::Conf::Parser::BEGIN@140
# spent 350µs making 1 call to Exporter::import |
141 | 2 | 73µs | 1 | 14µs | # spent 14µs within Mail::SpamAssassin::Conf::Parser::BEGIN@141 which was called:
# once (14µs+0s) by Mail::SpamAssassin::Conf::BEGIN@88 at line 141 # spent 14µs making 1 call to Mail::SpamAssassin::Conf::Parser::BEGIN@141 |
142 | |||||
143 | 2 | 60µs | 2 | 49µs | # spent 38µs (28+11) within Mail::SpamAssassin::Conf::Parser::BEGIN@143 which was called:
# once (28µs+11µs) by Mail::SpamAssassin::Conf::BEGIN@88 at line 143 # spent 38µs making 1 call to Mail::SpamAssassin::Conf::Parser::BEGIN@143
# spent 11µs making 1 call to strict::import |
144 | 2 | 66µs | 2 | 93µs | # spent 57µs (20+37) within Mail::SpamAssassin::Conf::Parser::BEGIN@144 which was called:
# once (20µs+37µs) by Mail::SpamAssassin::Conf::BEGIN@88 at line 144 # spent 57µs making 1 call to Mail::SpamAssassin::Conf::Parser::BEGIN@144
# spent 36µs making 1 call to warnings::import |
145 | 2 | 60µs | 2 | 35µs | # spent 29µs (22+7) within Mail::SpamAssassin::Conf::Parser::BEGIN@145 which was called:
# once (22µs+7µs) by Mail::SpamAssassin::Conf::BEGIN@88 at line 145 # spent 29µs making 1 call to Mail::SpamAssassin::Conf::Parser::BEGIN@145
# spent 7µs making 1 call to bytes::import |
146 | 2 | 74µs | 2 | 159µs | # spent 90µs (21+69) within Mail::SpamAssassin::Conf::Parser::BEGIN@146 which was called:
# once (21µs+69µs) by Mail::SpamAssassin::Conf::BEGIN@88 at line 146 # spent 90µs making 1 call to Mail::SpamAssassin::Conf::Parser::BEGIN@146
# spent 69µs making 1 call to re::import |
147 | |||||
148 | 1 | 2µs | # spent 88µs (20+68) within Mail::SpamAssassin::Conf::Parser::BEGIN@148 which was called:
# once (20µs+68µs) by Mail::SpamAssassin::Conf::BEGIN@88 at line 150 | ||
149 | @ISA | ||||
150 | 1 | 4.39ms | 2 | 157µs | }; # spent 88µs making 1 call to Mail::SpamAssassin::Conf::Parser::BEGIN@148
# spent 68µs making 1 call to vars::import |
151 | |||||
152 | 1 | 14µs | @ISA = qw(); | ||
153 | |||||
154 | ########################################################################### | ||||
155 | |||||
156 | # spent 30µs within Mail::SpamAssassin::Conf::Parser::new which was called:
# once (30µs+0s) by Mail::SpamAssassin::Conf::new at line 4515 of Mail/SpamAssassin/Conf.pm | ||||
157 | 1 | 2µs | my $class = shift; | ||
158 | 1 | 3µs | $class = ref($class) || $class; | ||
159 | 1 | 2µs | my ($conf) = @_; | ||
160 | |||||
161 | 1 | 4µs | my $self = { | ||
162 | 'conf' => $conf | ||||
163 | }; | ||||
164 | |||||
165 | 1 | 3µs | $self->{command_luts} = { }; | ||
166 | 1 | 4µs | $self->{command_luts}->{frequent} = { }; | ||
167 | 1 | 3µs | $self->{command_luts}->{remaining} = { }; | ||
168 | |||||
169 | 1 | 2µs | bless ($self, $class); | ||
170 | 1 | 11µs | $self; | ||
171 | } | ||||
172 | |||||
173 | ########################################################################### | ||||
174 | |||||
175 | # spent 7.09ms (842µs+6.25) within Mail::SpamAssassin::Conf::Parser::register_commands which was called 16 times, avg 443µs/call:
# once (88µs+3.09ms) by Mail::SpamAssassin::Conf::new at line 4516 of Mail/SpamAssassin/Conf.pm
# once (49µs+855µs) by Mail::SpamAssassin::Plugin::TxRep::set_config at line 1058 of Mail/SpamAssassin/Plugin/TxRep.pm
# once (49µs+377µs) by Mail::SpamAssassin::Plugin::URIDNSBL::set_config at line 813 of Mail/SpamAssassin/Plugin/URIDNSBL.pm
# once (52µs+250µs) by Mail::SpamAssassin::Plugin::ReplaceTags::set_config at line 292 of Mail/SpamAssassin/Plugin/ReplaceTags.pm
# once (45µs+242µs) by Mail::SpamAssassin::Plugin::SPF::set_config at line 228 of Mail/SpamAssassin/Plugin/SPF.pm
# once (56µs+229µs) by Mail::SpamAssassin::Plugin::FreeMail::set_config at line 213 of Mail/SpamAssassin/Plugin/FreeMail.pm
# once (58µs+208µs) by Mail::SpamAssassin::Plugin::DKIM::set_config at line 502 of Mail/SpamAssassin/Plugin/DKIM.pm
# once (44µs+208µs) by Mail::SpamAssassin::Plugin::Hashcash::set_config at line 158 of Mail/SpamAssassin/Plugin/Hashcash.pm
# once (62µs+137µs) by Mail::SpamAssassin::Plugin::AutoLearnThreshold::set_config at line 146 of Mail/SpamAssassin/Plugin/AutoLearnThreshold.pm
# once (46µs+145µs) by Mail::SpamAssassin::Plugin::SpamCop::set_config at line 157 of Mail/SpamAssassin/Plugin/SpamCop.pm
# once (55µs+132µs) by Mail::SpamAssassin::Plugin::WhiteListSubject::set_config at line 109 of Mail/SpamAssassin/Plugin/WhiteListSubject.pm
# once (44µs+133µs) by Mail::SpamAssassin::Plugin::Razor2::set_config at line 134 of Mail/SpamAssassin/Plugin/Razor2.pm
# once (60µs+62µs) by Mail::SpamAssassin::Plugin::MIMEHeader::set_config at line 163 of Mail/SpamAssassin/Plugin/MIMEHeader.pm
# once (44µs+62µs) by Mail::SpamAssassin::Plugin::URIDetail::set_config at line 150 of Mail/SpamAssassin/Plugin/URIDetail.pm
# once (47µs+59µs) by Mail::SpamAssassin::Plugin::AskDNS::set_config at line 359 of Mail/SpamAssassin/Plugin/AskDNS.pm
# once (43µs+60µs) by Mail::SpamAssassin::Plugin::VBounce::set_config at line 90 of Mail/SpamAssassin/Plugin/VBounce.pm | ||||
176 | 16 | 35µs | my($self, $arrref) = @_; | ||
177 | 16 | 61µs | my $conf = $self->{conf}; | ||
178 | |||||
179 | 16 | 126µs | 16 | 2.16ms | $self->set_defaults_from_command_list($arrref); # spent 2.16ms making 16 calls to Mail::SpamAssassin::Conf::Parser::set_defaults_from_command_list, avg 135µs/call |
180 | 16 | 148µs | 16 | 4.09ms | $self->build_command_luts($arrref); # spent 4.09ms making 16 calls to Mail::SpamAssassin::Conf::Parser::build_command_luts, avg 256µs/call |
181 | 48 | 397µs | push(@{$conf->{registered_commands}}, @{$arrref}); | ||
182 | } | ||||
183 | |||||
184 | # spent 2.16ms within Mail::SpamAssassin::Conf::Parser::set_defaults_from_command_list which was called 16 times, avg 135µs/call:
# 16 times (2.16ms+0s) by Mail::SpamAssassin::Conf::Parser::register_commands at line 179, avg 135µs/call | ||||
185 | 16 | 39µs | my ($self, $arrref) = @_; | ||
186 | 16 | 50µs | my $conf = $self->{conf}; | ||
187 | 32 | 341µs | foreach my $cmd (@{$arrref}) { | ||
188 | # note! exists, not defined -- we want to be able to set | ||||
189 | # "undef" default values. | ||||
190 | 203 | 877µs | if (exists($cmd->{default})) { | ||
191 | 110 | 950µs | $conf->{$cmd->{setting}} = $cmd->{default}; | ||
192 | } | ||||
193 | } | ||||
194 | } | ||||
195 | |||||
196 | # spent 4.09ms within Mail::SpamAssassin::Conf::Parser::build_command_luts which was called 16 times, avg 256µs/call:
# 16 times (4.09ms+0s) by Mail::SpamAssassin::Conf::Parser::register_commands at line 180, avg 256µs/call | ||||
197 | 16 | 32µs | my ($self, $arrref) = @_; | ||
198 | |||||
199 | 16 | 48µs | my $conf = $self->{conf}; | ||
200 | |||||
201 | 16 | 30µs | my $set; | ||
202 | 32 | 304µs | foreach my $cmd (@{$arrref}) { | ||
203 | # first off, decide what set this is in. | ||||
204 | 210 | 722µs | if ($cmd->{is_frequent}) { $set = 'frequent'; } | ||
205 | 196 | 337µs | else { $set = 'remaining'; } | ||
206 | |||||
207 | # next, its priority (used to ensure frequently-used params | ||||
208 | # are parsed first) | ||||
209 | 203 | 456µs | my $cmdname = $cmd->{command} || $cmd->{setting}; | ||
210 | 203 | 1.45ms | $self->{command_luts}->{$set}->{$cmdname} = $cmd; | ||
211 | |||||
212 | 205 | 748µs | if ($cmd->{aliases} && scalar @{$cmd->{aliases}} > 0) { | ||
213 | 4 | 15µs | foreach my $name (@{$cmd->{aliases}}) { | ||
214 | 2 | 14µs | $self->{command_luts}->{$set}->{$name} = $cmd; | ||
215 | } | ||||
216 | } | ||||
217 | } | ||||
218 | } | ||||
219 | |||||
220 | ########################################################################### | ||||
221 | |||||
222 | # spent 4.68s (1.56+3.12) within Mail::SpamAssassin::Conf::Parser::parse which was called:
# once (1.56s+3.12s) by Mail::SpamAssassin::Conf::parse_rules at line 4623 of Mail/SpamAssassin/Conf.pm | ||||
223 | 1 | 4µs | my ($self, undef, $scoresonly) = @_; # leave $rules in $_[1] | ||
224 | |||||
225 | 1 | 3µs | my $conf = $self->{conf}; | ||
226 | 1 | 4µs | $self->{scoresonly} = $scoresonly; | ||
227 | |||||
228 | # Language selection: | ||||
229 | # See http://www.gnu.org/manual/glibc-2.2.5/html_node/Locale-Categories.html | ||||
230 | # and http://www.gnu.org/manual/glibc-2.2.5/html_node/Using-gettextized-software.html | ||||
231 | 1 | 4µs | my $lang = $ENV{'LANGUAGE'}; # LANGUAGE has the highest precedence but has a | ||
232 | 1 | 2µs | if ($lang) { # special format: The user may specify more than | ||
233 | $lang =~ s/:.*$//; # one language here, colon separated. We use the | ||||
234 | } # first one only (lazy bums we are :o) | ||||
235 | 1 | 4µs | $lang ||= $ENV{'LC_ALL'}; | ||
236 | 1 | 3µs | $lang ||= $ENV{'LC_MESSAGES'}; | ||
237 | 1 | 2µs | $lang ||= $ENV{'LANG'}; | ||
238 | 1 | 2µs | $lang ||= 'C'; # Nothing set means C/POSIX | ||
239 | |||||
240 | 1 | 22µs | 1 | 8µs | if ($lang =~ /^(C|POSIX)$/) { # spent 8µs making 1 call to Mail::SpamAssassin::Conf::Parser::CORE:match |
241 | 1 | 2µs | $lang = 'en_US'; # Our default language | ||
242 | } else { | ||||
243 | $lang =~ s/[@.+,].*$//; # Strip codeset, modifier/audience, etc. | ||||
244 | } # (eg. .utf8 or @euro) | ||||
245 | |||||
246 | # get fast-access handles on the command lookup tables | ||||
247 | 1 | 3µs | my $lut_frequent = $self->{command_luts}->{frequent}; | ||
248 | 1 | 3µs | my $lut_remaining = $self->{command_luts}->{remaining}; | ||
249 | 2 | 12µs | my %migrated_keys = map { $_ => 1 } | ||
250 | @Mail::SpamAssassin::Conf::MIGRATED_SETTINGS; | ||||
251 | |||||
252 | 1 | 3µs | $self->{currentfile} = '(no file)'; | ||
253 | 1 | 2µs | my $skip_parsing = 0; | ||
254 | 1 | 2µs | my @curfile_stack; | ||
255 | my @if_stack; | ||||
256 | 1 | 472µs | my @conf_lines = split (/\n/, $_[1]); | ||
257 | 1 | 2µs | my $line; | ||
258 | 1 | 4µs | $self->{if_stack} = \@if_stack; | ||
259 | 1 | 4µs | $self->{file_scoped_attrs} = { }; | ||
260 | |||||
261 | 1 | 4µs | my $keepmetadata = $conf->{main}->{keep_config_parsing_metadata}; | ||
262 | |||||
263 | 1 | 99.0ms | while (defined ($line = shift @conf_lines)) { | ||
264 | 16436 | 51.4ms | local ($1); # bug 3838: prevent random taint flagging of $1 | ||
265 | |||||
266 | # bug 5545: used to support testing rules in the ruleqa system | ||||
267 | 16436 | 25.6ms | if ($keepmetadata && $line =~ /^\#testrules/) { | ||
268 | $self->{file_scoped_attrs}->{testrules}++; | ||||
269 | next; | ||||
270 | } | ||||
271 | |||||
272 | # bug 6800: let X-Spam-Checker-Version also show what sa-update we are at | ||||
273 | 16436 | 203ms | 16436 | 44.9ms | if ($line =~ /^\# UPDATE version (\d+)$/) { # spent 44.9ms making 16436 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 3µs/call |
274 | 1 | 5µs | for ($self->{currentfile}) { # just aliasing, not a loop | ||
275 | 1 | 10µs | $conf->{update_version}{$_} = $1 if defined $_ && $_ ne '(no file)'; | ||
276 | } | ||||
277 | } | ||||
278 | |||||
279 | 16436 | 212ms | 16436 | 64.6ms | $line =~ s/(?<!\\)#.*$//; # remove comments # spent 64.6ms making 16436 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 4µs/call |
280 | 16436 | 147ms | 16436 | 32.7ms | $line =~ s/\\#/#/g; # hash chars are escaped, so unescape them # spent 32.7ms making 16436 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 2µs/call |
281 | 16436 | 172ms | 16436 | 39.5ms | $line =~ s/^\s+//; # remove leading whitespace # spent 39.5ms making 16436 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 2µs/call |
282 | 16436 | 200ms | 16436 | 54.7ms | $line =~ s/\s+$//; # remove tailing whitespace # spent 54.7ms making 16436 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 3µs/call |
283 | 16436 | 38.0ms | next unless($line); # skip empty lines | ||
284 | |||||
285 | # handle i18n | ||||
286 | 10524 | 128ms | 11998 | 31.7ms | if ($line =~ s/^lang\s+(\S+)\s+//) { next if ($lang !~ /^$1/i); } # spent 22.0ms making 9050 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 2µs/call
# spent 6.07ms making 1474 calls to Mail::SpamAssassin::Conf::Parser::CORE:regcomp, avg 4µs/call
# spent 3.60ms making 1474 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 2µs/call |
287 | |||||
288 | 7576 | 57.4ms | my($key, $value) = split(/\s+/, $line, 2); | ||
289 | 7576 | 18.7ms | $key = lc $key; | ||
290 | # convert all dashes in setting name to underscores. | ||||
291 | 7576 | 84.5ms | 7576 | 17.2ms | $key =~ s/-/_/g; # spent 17.2ms making 7576 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 2µs/call |
292 | 7576 | 13.6ms | $value = '' unless defined($value); | ||
293 | |||||
294 | # # Do a better job untainting this info ... | ||||
295 | # # $value = untaint_var($value); | ||||
296 | # Do NOT blindly untaint now, do it carefully later when semantics is known! | ||||
297 | |||||
298 | 7576 | 12.2ms | my $parse_error; # undef by default, may be overridden | ||
299 | |||||
300 | # File/line number assertions | ||||
301 | 7576 | 14.1ms | if ($key eq 'file') { | ||
302 | 136 | 1.78ms | 136 | 734µs | if ($value =~ /^start\s+(.+)$/) { # spent 734µs making 136 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 5µs/call |
303 | 68 | 310µs | push (@curfile_stack, $self->{currentfile}); | ||
304 | 68 | 326µs | $self->{currentfile} = $1; | ||
305 | 68 | 319µs | next; | ||
306 | } | ||||
307 | |||||
308 | 68 | 859µs | 68 | 382µs | if ($value =~ /^end\s/) { # spent 382µs making 68 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 6µs/call |
309 | 68 | 327µs | $self->{file_scoped_attrs} = { }; | ||
310 | |||||
311 | 68 | 192µs | if (scalar @if_stack > 0) { | ||
312 | my $cond = pop @if_stack; | ||||
313 | |||||
314 | if ($cond->{type} eq 'if') { | ||||
315 | my $msg = "config: unclosed 'if' in ". | ||||
316 | $self->{currentfile}.": if ".$cond->{conditional}."\n"; | ||||
317 | warn $msg; | ||||
318 | $self->lint_warn($msg, undef); | ||||
319 | } | ||||
320 | else { | ||||
321 | # die seems a bit excessive here, but this shouldn't be possible | ||||
322 | # so I suppose it's okay. | ||||
323 | die "config: unknown 'if' type: ".$cond->{type}."\n"; | ||||
324 | } | ||||
325 | |||||
326 | @if_stack = (); | ||||
327 | } | ||||
328 | 68 | 138µs | $skip_parsing = 0; | ||
329 | |||||
330 | 68 | 351µs | my $curfile = pop @curfile_stack; | ||
331 | 68 | 253µs | if (defined $curfile) { | ||
332 | 68 | 260µs | $self->{currentfile} = $curfile; | ||
333 | } else { | ||||
334 | $self->{currentfile} = '(no file)'; | ||||
335 | } | ||||
336 | 68 | 315µs | next; | ||
337 | } | ||||
338 | } | ||||
339 | |||||
340 | # now handle the commands. | ||||
341 | 7440 | 12.7ms | if ($key eq 'include') { | ||
342 | 58 | 653µs | 58 | 23.2ms | $value = $self->fix_path_relative_to_current_file($value); # spent 23.2ms making 58 calls to Mail::SpamAssassin::Conf::Parser::fix_path_relative_to_current_file, avg 400µs/call |
343 | 58 | 795µs | 58 | 26.7ms | my $text = $conf->{main}->read_cf($value, 'included file'); # spent 26.7ms making 58 calls to Mail::SpamAssassin::read_cf, avg 461µs/call |
344 | 58 | 29.0ms | unshift (@conf_lines, split (/\n/, $text)); | ||
345 | 58 | 733µs | next; | ||
346 | } | ||||
347 | |||||
348 | 7382 | 12.7ms | if ($key eq 'ifplugin') { | ||
349 | 360 | 5.39ms | 360 | 130ms | $self->handle_conditional ($key, "plugin ($value)", # spent 130ms making 360 calls to Mail::SpamAssassin::Conf::Parser::handle_conditional, avg 361µs/call |
350 | \@if_stack, \$skip_parsing); | ||||
351 | 360 | 1.58ms | next; | ||
352 | } | ||||
353 | |||||
354 | 7022 | 11.7ms | if ($key eq 'if') { | ||
355 | 148 | 1.65ms | 148 | 80.7ms | $self->handle_conditional ($key, $value, # spent 80.7ms making 148 calls to Mail::SpamAssassin::Conf::Parser::handle_conditional, avg 546µs/call |
356 | \@if_stack, \$skip_parsing); | ||||
357 | 148 | 663µs | next; | ||
358 | } | ||||
359 | |||||
360 | 6874 | 11.5ms | if ($key eq 'else') { | ||
361 | # TODO: if/else/else won't get flagged here :( | ||||
362 | 2 | 4µs | if (!@if_stack) { | ||
363 | $parse_error = "config: found else without matching conditional"; | ||||
364 | goto failed_line; | ||||
365 | } | ||||
366 | |||||
367 | 2 | 6µs | $skip_parsing = !$skip_parsing; | ||
368 | 2 | 7µs | next; | ||
369 | } | ||||
370 | |||||
371 | # and the endif statement: | ||||
372 | 6872 | 11.7ms | if ($key eq 'endif') { | ||
373 | 508 | 1.12ms | my $lastcond = pop @if_stack; | ||
374 | 508 | 878µs | if (!defined $lastcond) { | ||
375 | $parse_error = "config: found endif without matching conditional"; | ||||
376 | goto failed_line; | ||||
377 | } | ||||
378 | |||||
379 | 508 | 1.18ms | $skip_parsing = $lastcond->{skip_parsing}; | ||
380 | 508 | 6.33ms | next; | ||
381 | } | ||||
382 | |||||
383 | # preprocessing? skip all other commands | ||||
384 | 6364 | 10.4ms | next if $skip_parsing; | ||
385 | |||||
386 | 6184 | 10.3ms | if ($key eq 'require_version') { | ||
387 | # if it wasn't replaced during install, assume current version ... | ||||
388 | 17 | 49µs | next if ($value eq "\@\@VERSION\@\@"); | ||
389 | |||||
390 | 17 | 43µs | my $ver = $Mail::SpamAssassin::VERSION; | ||
391 | |||||
392 | # if we want to allow "require_version 3.0" be good for all | ||||
393 | # "3.0.x" versions: | ||||
394 | ## make sure it's a numeric value | ||||
395 | #$value += 0.0; | ||||
396 | ## convert 3.000000 -> 3.0, stay backward compatible ... | ||||
397 | #$ver =~ s/^(\d+)\.(\d{1,3}).*$/sprintf "%d.%d", $1, $2/e; | ||||
398 | #$value =~ s/^(\d+)\.(\d{1,3}).*$/sprintf "%d.%d", $1, $2/e; | ||||
399 | |||||
400 | 17 | 48µs | if ($ver ne $value) { | ||
401 | my $msg = "config: configuration file \"$self->{currentfile}\" requires ". | ||||
402 | "version $value of SpamAssassin, but this is code version ". | ||||
403 | "$ver. Maybe you need to use ". | ||||
404 | "the -C switch, or remove the old config files? ". | ||||
405 | "Skipping this file"; | ||||
406 | warn $msg; | ||||
407 | $self->lint_warn($msg, undef); | ||||
408 | $skip_parsing = 1; | ||||
409 | } | ||||
410 | 17 | 88µs | next; | ||
411 | } | ||||
412 | |||||
413 | 6167 | 15.2ms | my $cmd = $lut_frequent->{$key}; # check the frequent command set | ||
414 | 6167 | 13.9ms | if (!$cmd) { | ||
415 | 2208 | 5.29ms | $cmd = $lut_remaining->{$key}; # no? try the rest | ||
416 | } | ||||
417 | |||||
418 | # we've either fallen through with no match, in which case this | ||||
419 | # if() will fail, or we have a match. | ||||
420 | 6167 | 10.1ms | if ($cmd) { | ||
421 | 5666 | 10.4ms | if ($self->{scoresonly}) { # reading user config from spamd | ||
422 | if ($cmd->{is_priv} && !$conf->{allow_user_rules}) { | ||||
423 | info("config: not parsing, 'allow_user_rules' is 0: $line"); | ||||
424 | goto failed_line; | ||||
425 | } | ||||
426 | if ($cmd->{is_admin}) { | ||||
427 | info("config: not parsing, administrator setting: $line"); | ||||
428 | goto failed_line; | ||||
429 | } | ||||
430 | } | ||||
431 | |||||
432 | 5666 | 12.1ms | if (!$cmd->{code}) { | ||
433 | 21 | 159µs | 21 | 510µs | if (! $self->setup_default_code_cb($cmd)) { # spent 510µs making 21 calls to Mail::SpamAssassin::Conf::Parser::setup_default_code_cb, avg 24µs/call |
434 | goto failed_line; | ||||
435 | } | ||||
436 | } | ||||
437 | |||||
438 | 11332 | 66.0ms | 5666 | 2.13s | my $ret = &{$cmd->{code}} ($conf, $cmd->{setting}, $value, $line); # spent 581ms making 27 calls to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:4145], avg 21.5ms/call
# spent 302ms making 465 calls to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:3174], avg 649µs/call
# spent 282ms making 781 calls to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:2981], avg 361µs/call
# spent 260ms making 1276 calls to Mail::SpamAssassin::Conf::Parser::set_hash_key_value, avg 203µs/call
# spent 228ms making 655 calls to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:3020], avg 349µs/call
# spent 156ms making 811 calls to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:280], avg 192µs/call
# spent 97.7ms making 30 calls to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:1685], avg 3.26ms/call
# spent 45.4ms making 46 calls to Mail::SpamAssassin::Plugin::MIMEHeader::__ANON__[Mail/SpamAssassin/Plugin/MIMEHeader.pm:160], avg 986µs/call
# spent 34.5ms making 459 calls to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:3750], avg 75µs/call
# spent 30.3ms making 71 calls to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:3052], avg 427µs/call
# spent 24.8ms making 128 calls to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:3557], avg 194µs/call
# spent 22.7ms making 83 calls to Mail::SpamAssassin::Plugin::DKIM::__ANON__[Mail/SpamAssassin/Plugin/DKIM.pm:420], avg 274µs/call
# spent 13.4ms making 40 calls to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:3088], avg 335µs/call
# spent 8.03ms making 64 calls to Mail::SpamAssassin::Plugin::ReplaceTags::__ANON__[Mail/SpamAssassin/Plugin/ReplaceTags.pm:266], avg 126µs/call
# spent 5.17ms making 85 calls to Mail::SpamAssassin::Plugin::DKIM::__ANON__[Mail/SpamAssassin/Plugin/DKIM.pm:468], avg 61µs/call
# spent 5.01ms making 270 calls to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:2044], avg 19µs/call
# spent 4.99ms making 15 calls to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:2701], avg 333µs/call
# spent 4.60ms making 34 calls to Mail::SpamAssassin::Conf::Parser::set_addrlist_value, avg 135µs/call
# spent 3.88ms making 21 calls to Mail::SpamAssassin::Plugin::URIDNSBL::__ANON__[Mail/SpamAssassin/Plugin/URIDNSBL.pm:662], avg 185µs/call
# spent 3.64ms making 63 calls to Mail::SpamAssassin::Plugin::URIDNSBL::__ANON__[Mail/SpamAssassin/Plugin/URIDNSBL.pm:783], avg 58µs/call
# spent 2.87ms making 19 calls to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:433], avg 151µs/call
# spent 2.66ms making 77 calls to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:3206], avg 35µs/call
# spent 2.29ms making 48 calls to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:3781], avg 48µs/call
# spent 2.09ms making 13 calls to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:3122], avg 161µs/call
# spent 1.25ms making 1 call to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:3804]
# spent 1.05ms making 5 calls to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:935], avg 211µs/call
# spent 680µs making 2 calls to Mail::SpamAssassin::Plugin::AskDNS::__ANON__[Mail/SpamAssassin/Plugin/AskDNS.pm:356], avg 340µs/call
# spent 542µs making 17 calls to Mail::SpamAssassin::Conf::Parser::set_template_append, avg 32µs/call
# spent 394µs making 4 calls to Mail::SpamAssassin::Conf::Parser::set_numeric_value, avg 99µs/call
# spent 314µs making 1 call to Mail::SpamAssassin::Plugin::URIDNSBL::__ANON__[Mail/SpamAssassin/Plugin/URIDNSBL.pm:609]
# spent 255µs making 5 calls to Mail::SpamAssassin::Conf::Parser::set_bool_value, avg 51µs/call
# spent 201µs making 2 calls to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:1419], avg 100µs/call
# spent 195µs making 36 calls to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:3402], avg 5µs/call
# spent 94µs making 3 calls to Mail::SpamAssassin::Conf::Parser::set_string_value, avg 31µs/call
# spent 87µs making 1 call to Mail::SpamAssassin::Plugin::URIDNSBL::__ANON__[Mail/SpamAssassin/Plugin/URIDNSBL.pm:581]
# spent 85µs making 1 call to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:3835]
# spent 80µs making 1 call to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:3858]
# spent 56µs making 1 call to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:1007]
# spent 52µs making 2 calls to Mail::SpamAssassin::Conf::Parser::set_template_clear, avg 26µs/call
# spent 48µs making 1 call to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:1054]
# spent 32µs making 1 call to Mail::SpamAssassin::Plugin::TxRep::__ANON__[Mail/SpamAssassin/Plugin/TxRep.pm:491]
# spent 22µs making 1 call to Mail::SpamAssassin::Conf::__ANON__[Mail/SpamAssassin/Conf.pm:1437] |
439 | |||||
440 | 5666 | 13.3ms | if ($ret && $ret eq $Mail::SpamAssassin::Conf::INVALID_VALUE) | ||
441 | { | ||||
442 | $parse_error = "config: SpamAssassin failed to parse line, ". | ||||
443 | "\"$value\" is not valid for \"$key\", ". | ||||
444 | "skipping: $line"; | ||||
445 | goto failed_line; | ||||
446 | } | ||||
447 | elsif ($ret && $ret eq $Mail::SpamAssassin::Conf::INVALID_HEADER_FIELD_NAME) | ||||
448 | { | ||||
449 | $parse_error = "config: SpamAssassin failed to parse line, ". | ||||
450 | "it does not specify a valid header field name, ". | ||||
451 | "skipping: $line"; | ||||
452 | goto failed_line; | ||||
453 | } | ||||
454 | elsif ($ret && $ret eq $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE) | ||||
455 | { | ||||
456 | $parse_error = "config: SpamAssassin failed to parse line, ". | ||||
457 | "no value provided for \"$key\", ". | ||||
458 | "skipping: $line"; | ||||
459 | goto failed_line; | ||||
460 | } | ||||
461 | else { | ||||
462 | 5666 | 26.1ms | next; | ||
463 | } | ||||
464 | } | ||||
465 | |||||
466 | # last ditch: try to see if the plugins know what to do with it | ||||
467 | 501 | 5.68ms | 501 | 167ms | if ($conf->{main}->call_plugins("parse_config", { # spent 167ms making 501 calls to Mail::SpamAssassin::call_plugins, avg 334µs/call |
468 | key => $key, | ||||
469 | value => $value, | ||||
470 | line => $line, | ||||
471 | conf => $conf, | ||||
472 | user_config => $self->{scoresonly} | ||||
473 | })) | ||||
474 | { | ||||
475 | # a plugin dealt with it successfully. | ||||
476 | 501 | 2.72ms | next; | ||
477 | } | ||||
478 | |||||
479 | failed_line: | ||||
480 | my $msg = $parse_error; | ||||
481 | my $is_error = 1; | ||||
482 | if (!$msg) { | ||||
483 | # use a default warning, if a more specific one wasn't output | ||||
484 | if ($migrated_keys{$key}) { | ||||
485 | # this key was moved into a plugin; non-fatal for lint | ||||
486 | $is_error = 0; | ||||
487 | $msg = "config: failed to parse, now a plugin, skipping, in \"$self->{currentfile}\": $line"; | ||||
488 | } else { | ||||
489 | # a real syntax error; this is fatal for --lint | ||||
490 | $msg = "config: failed to parse line, skipping, in \"$self->{currentfile}\": $line"; | ||||
491 | } | ||||
492 | } | ||||
493 | |||||
494 | $self->lint_warn($msg, undef, $is_error); | ||||
495 | } | ||||
496 | |||||
497 | 1 | 6µs | delete $self->{if_stack}; | ||
498 | |||||
499 | 1 | 9µs | 1 | 13µs | $self->lint_check(); # spent 13µs making 1 call to Mail::SpamAssassin::Conf::Parser::lint_check |
500 | 1 | 8µs | 1 | 123ms | $self->set_default_scores(); # spent 123ms making 1 call to Mail::SpamAssassin::Conf::Parser::set_default_scores |
501 | 1 | 17µs | 1 | 154ms | $self->check_for_missing_descriptions(); # spent 154ms making 1 call to Mail::SpamAssassin::Conf::Parser::check_for_missing_descriptions |
502 | |||||
503 | 1 | 26µs | delete $self->{scoresonly}; | ||
504 | } | ||||
505 | |||||
506 | # spent 211ms (142+68.6) within Mail::SpamAssassin::Conf::Parser::handle_conditional which was called 508 times, avg 415µs/call:
# 360 times (87.7ms+42.3ms) by Mail::SpamAssassin::Conf::Parser::parse at line 349, avg 361µs/call
# 148 times (54.4ms+26.3ms) by Mail::SpamAssassin::Conf::Parser::parse at line 355, avg 546µs/call | ||||
507 | 508 | 2.61ms | my ($self, $key, $value, $if_stack_ref, $skip_parsing_ref) = @_; | ||
508 | 508 | 1.31ms | my $conf = $self->{conf}; | ||
509 | |||||
510 | 508 | 894µs | my $lexer = ARITH_EXPRESSION_LEXER; | ||
511 | 508 | 20.0ms | 1016 | 10.3ms | my @tokens = ($value =~ m/($lexer)/g); # spent 7.34ms making 508 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 14µs/call
# spent 3.00ms making 508 calls to Mail::SpamAssassin::Conf::Parser::CORE:regcomp, avg 6µs/call |
512 | |||||
513 | 508 | 1.05ms | my $eval = ''; | ||
514 | 508 | 894µs | my $bad = 0; | ||
515 | 508 | 2.19ms | foreach my $token (@tokens) { | ||
516 | 2161 | 60.8ms | 2650 | 10.6ms | if ($token =~ /^(?:\W+|[+-]?\d+(?:\.\d+)?)$/) { # spent 10.6ms making 2650 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 4µs/call |
517 | # using tainted subr. argument may taint the whole expression, avoid | ||||
518 | 1164 | 7.93ms | 1164 | 27.6ms | my $u = untaint_var($token); # spent 27.6ms making 1164 calls to Mail::SpamAssassin::Util::untaint_var, avg 24µs/call |
519 | 1164 | 2.70ms | $eval .= $u . " "; | ||
520 | } | ||||
521 | elsif ($token eq 'plugin') { | ||||
522 | # replace with a method call | ||||
523 | 434 | 859µs | $eval .= '$self->cond_clause_plugin_loaded'; | ||
524 | } | ||||
525 | elsif ($token eq 'can') { | ||||
526 | # replace with a method call | ||||
527 | 55 | 131µs | $eval .= '$self->cond_clause_can'; | ||
528 | } | ||||
529 | elsif ($token eq 'has') { | ||||
530 | # replace with a method call | ||||
531 | $eval .= '$self->cond_clause_has'; | ||||
532 | } | ||||
533 | elsif ($token eq 'version') { | ||||
534 | 19 | 62µs | $eval .= $Mail::SpamAssassin::VERSION." "; | ||
535 | } | ||||
536 | elsif ($token eq 'perl_version') { | ||||
537 | $eval .= $]." "; | ||||
538 | } | ||||
539 | elsif ($token =~ /^\w[\w\:]+$/) { # class name | ||||
540 | 489 | 3.34ms | 489 | 11.0ms | my $u = untaint_var($token); # spent 11.0ms making 489 calls to Mail::SpamAssassin::Util::untaint_var, avg 22µs/call |
541 | 489 | 1.30ms | $eval .= '"' . $u . '" '; | ||
542 | } | ||||
543 | else { | ||||
544 | $bad++; | ||||
545 | warn "config: unparseable chars in 'if $value': '$token'\n"; | ||||
546 | } | ||||
547 | } | ||||
548 | |||||
549 | 508 | 929µs | if ($bad) { | ||
550 | $self->lint_warn("bad 'if' line, in \"$self->{currentfile}\"", undef); | ||||
551 | return -1; | ||||
552 | } | ||||
553 | |||||
554 | 1016 | 5.41ms | push (@{$if_stack_ref}, { | ||
555 | type => 'if', | ||||
556 | conditional => $value, | ||||
557 | skip_parsing => $$skip_parsing_ref | ||||
558 | }); | ||||
559 | |||||
560 | 508 | 41.7ms | if (eval $eval) { # spent 875µs executing statements in 72 string evals (merged)
# spent 675µs executing statements in 59 string evals (merged)
# spent 507µs executing statements in 41 string evals (merged)
# spent 382µs executing statements in 26 string evals (merged)
# spent 335µs executing statements in 25 string evals (merged)
# spent 326µs executing statements in 20 string evals (merged)
# spent 255µs executing statements in 21 string evals (merged)
# spent 197µs executing statements in 14 string evals (merged)
# spent 189µs executing statements in 15 string evals (merged)
# spent 162µs executing statements in 13 string evals (merged)
# spent 142µs executing statements in 12 string evals (merged)
# spent 135µs executing statements in 11 string evals (merged)
# spent 131µs executing statements in 11 string evals (merged)
# spent 109µs executing statements in 6 string evals (merged)
# spent 102µs executing statements in 7 string evals (merged)
# spent 102µs executing statements in 8 string evals (merged)
# spent 100µs executing statements in 6 string evals (merged)
# spent 100µs executing statements in 7 string evals (merged)
# spent 96µs executing statements in 7 string evals (merged)
# spent 87µs executing statements in 7 string evals (merged)
# spent 76µs executing statements in 5 string evals (merged)
# spent 75µs executing statements in 7 string evals (merged)
# spent 75µs executing statements in 7 string evals (merged)
# spent 73µs executing statements in 5 string evals (merged)
# spent 72µs executing statements in 6 string evals (merged)
# spent 71µs executing statements in 12 string evals (merged)
# spent 64µs executing statements in 5 string evals (merged)
# spent 63µs executing statements in 5 string evals (merged)
# spent 56µs executing statements in 5 string evals (merged)
# spent 50µs executing statements in 4 string evals (merged)
# spent 49µs executing statements in 4 string evals (merged)
# spent 49µs executing statements in 4 string evals (merged)
# spent 48µs executing statements in 3 string evals (merged)
# spent 43µs executing statements in 3 string evals (merged)
# spent 42µs executing statements in 2 string evals (merged)
# spent 41µs executing statements in 3 string evals (merged)
# spent 41µs executing statements in 2 string evals (merged)
# spent 40µs executing statements in 3 string evals (merged)
# spent 32µs executing statements in 2 string evals (merged)
# spent 30µs executing statements in 2 string evals (merged)
# spent 30µs executing statements in 2 string evals (merged)
# spent 29µs executing statements in 2 string evals (merged)
# spent 28µs executing statements in 2 string evals (merged)
# spent 28µs executing statements in 2 string evals (merged)
# spent 24µs executing statements in 2 string evals (merged)
# spent 23µs executing statements in string eval
# spent 23µs executing statements in string eval
# spent 22µs executing statements in 2 string evals (merged)
# spent 20µs executing statements in string eval
# spent 17µs executing statements in string eval
# spent 17µs executing statements in string eval
# spent 16µs executing statements in string eval
# spent 16µs executing statements in 3 string evals (merged)
# spent 14µs executing statements in string eval
# spent 14µs executing statements in string eval
# spent 13µs executing statements in string eval
# spent 12µs executing statements in 2 string evals (merged)
# spent 11µs executing statements in string eval
# spent 11µs executing statements in string eval
# spent 10µs executing statements in string eval
# spent 10µs executing statements in string eval
# spent 6µs executing statements in string eval | ||
561 | # leave $skip_parsing as-is; we may not be parsing anyway in this block. | ||||
562 | # in other words, support nested 'if's and 'require_version's | ||||
563 | } else { | ||||
564 | 127 | 297µs | warn "config: error in $key - $eval: $@" if $@ ne ''; | ||
565 | 127 | 269µs | $$skip_parsing_ref = 1; | ||
566 | } | ||||
567 | } | ||||
568 | |||||
569 | # functions supported in the "if" eval: | ||||
570 | # spent 3.99ms within Mail::SpamAssassin::Conf::Parser::cond_clause_plugin_loaded which was called 434 times, avg 9µs/call:
# 72 times (619µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 119)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 9µs/call
# 59 times (467µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 287)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 8µs/call
# 41 times (356µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 132)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 9µs/call
# 26 times (225µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 823)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 9µs/call
# 25 times (243µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 154)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 10µs/call
# 20 times (144µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 742)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 7µs/call
# 15 times (118µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 289)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 8µs/call
# 14 times (166µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 128)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 12µs/call
# 13 times (107µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 126)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 8µs/call
# 12 times (115µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 279)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 10µs/call
# 11 times (111µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 170)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 10µs/call
# 11 times (110µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 201)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 10µs/call
# 8 times (47µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 115)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 6µs/call
# 7 times (85µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 754)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 12µs/call
# 7 times (83µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 275)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 12µs/call
# 7 times (71µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 274)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 10µs/call
# 7 times (65µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 278)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 9µs/call
# 7 times (49µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 276)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 7µs/call
# 6 times (69µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 523)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 12µs/call
# 6 times (56µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 285)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 9µs/call
# 5 times (64µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 296)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 13µs/call
# 5 times (49µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 207)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 10µs/call
# 5 times (49µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 335)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 10µs/call
# 5 times (45µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 473)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 9µs/call
# 4 times (58µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 347)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 15µs/call
# 4 times (51µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 284)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 13µs/call
# 4 times (28µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 945)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 7µs/call
# 3 times (45µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 131)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 15µs/call
# 3 times (18µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 304)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 6µs/call
# 2 times (34µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 129)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 17µs/call
# 2 times (31µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 286)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 15µs/call
# 2 times (30µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 348)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 15µs/call
# 2 times (26µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 363)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 13µs/call
# 2 times (25µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 133)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 13µs/call
# 2 times (21µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 261)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 11µs/call
# 2 times (21µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 925)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 10µs/call
# 2 times (11µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 1007)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 5µs/call
# once (18µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 942)[Mail/SpamAssassin/Conf/Parser.pm:560]
# once (16µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 116)[Mail/SpamAssassin/Conf/Parser.pm:560]
# once (15µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 1062)[Mail/SpamAssassin/Conf/Parser.pm:560]
# once (12µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 231)[Mail/SpamAssassin/Conf/Parser.pm:560]
# once (12µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 277)[Mail/SpamAssassin/Conf/Parser.pm:560]
# once (7µs+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 372)[Mail/SpamAssassin/Conf/Parser.pm:560] | ||||
571 | 434 | 9.07ms | return $_[0]->{conf}->{plugins_loaded}->{$_[1]}; | ||
572 | } | ||||
573 | |||||
574 | # spent 5.14ms (942µs+4.20) within Mail::SpamAssassin::Conf::Parser::cond_clause_can which was called 55 times, avg 93µs/call:
# 21 times (346µs+1.42ms) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 634)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 84µs/call
# 7 times (102µs+510µs) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 932)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 87µs/call
# 6 times (108µs+506µs) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 718)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 102µs/call
# 5 times (98µs+413µs) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 290)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 102µs/call
# 3 times (54µs+236µs) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 947)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 97µs/call
# 3 times (49µs+228µs) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 940)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 92µs/call
# 2 times (27µs+180µs) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 531)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 103µs/call
# 2 times (30µs+170µs) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 120)[Mail/SpamAssassin/Conf/Parser.pm:560], avg 100µs/call
# once (32µs+95µs) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 299)[Mail/SpamAssassin/Conf/Parser.pm:560]
# once (21µs+94µs) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 114)[Mail/SpamAssassin/Conf/Parser.pm:560]
# once (18µs+88µs) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 529)[Mail/SpamAssassin/Conf/Parser.pm:560]
# once (26µs+79µs) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 1075)[Mail/SpamAssassin/Conf/Parser.pm:560]
# once (12µs+93µs) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 118)[Mail/SpamAssassin/Conf/Parser.pm:560]
# once (19µs+82µs) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 1 of (eval 117)[Mail/SpamAssassin/Conf/Parser.pm:560] | ||||
575 | 55 | 128µs | my ($self, $method) = @_; | ||
576 | 55 | 1.12ms | 55 | 4.20ms | $self->cond_clause_can_or_has('can', $method); # spent 4.20ms making 55 calls to Mail::SpamAssassin::Conf::Parser::cond_clause_can_or_has, avg 76µs/call |
577 | } | ||||
578 | |||||
579 | sub cond_clause_has { | ||||
580 | my ($self, $method) = @_; | ||||
581 | $self->cond_clause_can_or_has('has', $method); | ||||
582 | } | ||||
583 | |||||
584 | # spent 4.20ms (2.63+1.56) within Mail::SpamAssassin::Conf::Parser::cond_clause_can_or_has which was called 55 times, avg 76µs/call:
# 55 times (2.63ms+1.56ms) by Mail::SpamAssassin::Conf::Parser::cond_clause_can at line 576, avg 76µs/call | ||||
585 | 55 | 118µs | my ($self, $fn_name, $method) = @_; | ||
586 | |||||
587 | 55 | 269µs | local($1,$2); | ||
588 | 55 | 963µs | 55 | 461µs | if (!defined $method) { # spent 461µs making 55 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 8µs/call |
589 | $self->lint_warn("bad 'if' line, no argument to $fn_name(), ". | ||||
590 | "in \"$self->{currentfile}\"", undef); | ||||
591 | } elsif ($method =~ /^(.*)::([^:]+)$/) { | ||||
592 | 2 | 10.8ms | 2 | 154µs | # spent 95µs (37+59) within Mail::SpamAssassin::Conf::Parser::BEGIN@592 which was called:
# once (37µs+59µs) by Mail::SpamAssassin::Conf::BEGIN@88 at line 592 # spent 95µs making 1 call to Mail::SpamAssassin::Conf::Parser::BEGIN@592
# spent 59µs making 1 call to strict::unimport |
593 | 55 | 256µs | my($module, $meth) = ($1, $2); | ||
594 | return 1 if UNIVERSAL::can($module,$meth) && | ||||
595 | 110 | 2.36ms | 110 | 1.10ms | ( $fn_name eq 'has' || &{$method}() ); # spent 570µs making 55 calls to UNIVERSAL::can, avg 10µs/call
# spent 192µs making 24 calls to Mail::SpamAssassin::Conf::feature_bug6558_free, avg 8µs/call
# spent 96µs making 10 calls to Mail::SpamAssassin::Plugin::BodyEval::has_check_body_length, avg 10µs/call
# spent 88µs making 7 calls to Mail::SpamAssassin::Conf::perl_min_version_5010000, avg 13µs/call
# spent 43µs making 5 calls to Mail::SpamAssassin::Plugin::SPF::has_check_for_spf_errors, avg 9µs/call
# spent 29µs making 2 calls to Mail::SpamAssassin::Conf::feature_registryboundaries, avg 14µs/call
# spent 24µs making 2 calls to Mail::SpamAssassin::Plugin::MIMEEval::has_check_abundant_unicode_ratio, avg 12µs/call
# spent 18µs making 1 call to Mail::SpamAssassin::Conf::feature_dns_local_ports_permit_avoid
# spent 15µs making 1 call to Mail::SpamAssassin::Conf::feature_originating_ip_headers
# spent 10µs making 1 call to Mail::SpamAssassin::Plugin::MIMEEval::has_check_for_ascii_text_illegal
# spent 9µs making 1 call to Mail::SpamAssassin::Conf::feature_yesno_takes_args
# spent 8µs making 1 call to Mail::SpamAssassin::Plugin::URIDNSBL::has_tflags_domains_only |
596 | } else { | ||||
597 | $self->lint_warn("bad 'if' line, cannot find '::' in $fn_name($method), ". | ||||
598 | "in \"$self->{currentfile}\"", undef); | ||||
599 | } | ||||
600 | return; | ||||
601 | } | ||||
602 | |||||
603 | # Let's do some linting here ... | ||||
604 | # This is called from _parse(), BTW, so we can check for $conf->{tests} | ||||
605 | # easily before finish_parsing() is called and deletes it. | ||||
606 | # | ||||
607 | # spent 13µs within Mail::SpamAssassin::Conf::Parser::lint_check which was called:
# once (13µs+0s) by Mail::SpamAssassin::Conf::Parser::parse at line 499 | ||||
608 | 1 | 2µs | my ($self) = @_; | ||
609 | 1 | 3µs | my $conf = $self->{conf}; | ||
610 | |||||
611 | 1 | 12µs | if ($conf->{lint_rules}) { | ||
612 | # Check for description and score issues in lint fashion | ||||
613 | while ( my $k = each %{$conf->{descriptions}} ) { | ||||
614 | if (!exists $conf->{tests}->{$k}) { | ||||
615 | $self->lint_warn("config: warning: description exists for non-existent rule $k\n", $k); | ||||
616 | } | ||||
617 | } | ||||
618 | |||||
619 | while ( my($sk) = each %{$conf->{scores}} ) { | ||||
620 | if (!exists $conf->{tests}->{$sk}) { | ||||
621 | # bug 5514: not a lint warning any more | ||||
622 | dbg("config: warning: score set for non-existent rule $sk"); | ||||
623 | } | ||||
624 | } | ||||
625 | } | ||||
626 | } | ||||
627 | |||||
628 | # we should set a default score for all valid rules... Do this here | ||||
629 | # instead of add_test because mostly 'score' occurs after the rule is | ||||
630 | # specified, so why set the scores to default, then set them again at | ||||
631 | # 'score'? | ||||
632 | # | ||||
633 | # spent 123ms (119+4.59) within Mail::SpamAssassin::Conf::Parser::set_default_scores which was called:
# once (119ms+4.59ms) by Mail::SpamAssassin::Conf::Parser::parse at line 500 | ||||
634 | 1 | 2µs | my ($self) = @_; | ||
635 | 1 | 3µs | my $conf = $self->{conf}; | ||
636 | |||||
637 | 2069 | 33.4ms | while ( my $k = each %{$conf->{tests}} ) { | ||
638 | 2067 | 6.13ms | if ( ! exists $conf->{scores}->{$k} ) { | ||
639 | # T_ rules (in a testing probationary period) get low, low scores | ||||
640 | 1284 | 10.1ms | 1284 | 2.48ms | my $set_score = ($k =~/^T_/) ? 0.01 : 1.0; # spent 2.48ms making 1284 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 2µs/call |
641 | |||||
642 | 1284 | 23.2ms | 1284 | 2.10ms | $set_score = -$set_score if ( ($conf->{tflags}->{$k}||'') =~ /\bnice\b/ ); # spent 2.10ms making 1284 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 2µs/call |
643 | 1284 | 4.89ms | for my $index (0..3) { | ||
644 | 5136 | 45.6ms | $conf->{scoreset}->[$index]->{$k} = $set_score; | ||
645 | } | ||||
646 | } | ||||
647 | } | ||||
648 | } | ||||
649 | |||||
650 | # loop through all the tests and if we are missing a description with debug | ||||
651 | # set, throw a warning except for testing T_ or meta __ rules. | ||||
652 | # spent 154ms (63.0+91.0) within Mail::SpamAssassin::Conf::Parser::check_for_missing_descriptions which was called:
# once (63.0ms+91.0ms) by Mail::SpamAssassin::Conf::Parser::parse at line 501 | ||||
653 | 1 | 4µs | my ($self) = @_; | ||
654 | 1 | 3µs | my $conf = $self->{conf}; | ||
655 | |||||
656 | 2069 | 30.9ms | while ( my $k = each %{$conf->{tests}} ) { | ||
657 | 2067 | 24.9ms | 2067 | 6.61ms | if ($k !~ m/^(?:T_|__)/i) { # spent 6.61ms making 2067 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 3µs/call |
658 | 815 | 10.6ms | 815 | 83.9ms | if ( ! exists $conf->{descriptions}->{$k} ) { # spent 83.9ms making 815 calls to Mail::SpamAssassin::Util::TieOneStringHash::EXISTS, avg 103µs/call |
659 | 69 | 876µs | 69 | 441µs | dbg("config: warning: no description set for $k"); # spent 441µs making 69 calls to Mail::SpamAssassin::Logger::dbg, avg 6µs/call |
660 | } | ||||
661 | } | ||||
662 | } | ||||
663 | } | ||||
664 | |||||
665 | ########################################################################### | ||||
666 | |||||
667 | # spent 510µs within Mail::SpamAssassin::Conf::Parser::setup_default_code_cb which was called 21 times, avg 24µs/call:
# 21 times (510µs+0s) by Mail::SpamAssassin::Conf::Parser::parse at line 433, avg 24µs/call | ||||
668 | 21 | 42µs | my ($self, $cmd) = @_; | ||
669 | 21 | 166µs | my $type = $cmd->{type}; | ||
670 | |||||
671 | 21 | 119µs | if ($type == $Mail::SpamAssassin::Conf::CONF_TYPE_STRING) { | ||
672 | 3 | 9µs | $cmd->{code} = \&set_string_value; | ||
673 | } | ||||
674 | elsif ($type == $Mail::SpamAssassin::Conf::CONF_TYPE_BOOL) { | ||||
675 | 4 | 11µs | $cmd->{code} = \&set_bool_value; | ||
676 | } | ||||
677 | elsif ($type == $Mail::SpamAssassin::Conf::CONF_TYPE_NUMERIC) { | ||||
678 | 4 | 18µs | $cmd->{code} = \&set_numeric_value; | ||
679 | } | ||||
680 | elsif ($type == $Mail::SpamAssassin::Conf::CONF_TYPE_HASH_KEY_VALUE) { | ||||
681 | 6 | 20µs | $cmd->{code} = \&set_hash_key_value; | ||
682 | } | ||||
683 | elsif ($type == $Mail::SpamAssassin::Conf::CONF_TYPE_ADDRLIST) { | ||||
684 | 2 | 9µs | $cmd->{code} = \&set_addrlist_value; | ||
685 | } | ||||
686 | elsif ($type == $Mail::SpamAssassin::Conf::CONF_TYPE_TEMPLATE) { | ||||
687 | 2 | 7µs | $cmd->{code} = \&set_template_append; | ||
688 | } | ||||
689 | elsif ($type == $Mail::SpamAssassin::Conf::CONF_TYPE_NOARGS) { | ||||
690 | $cmd->{code} = \&set_no_value; | ||||
691 | } | ||||
692 | elsif ($type == $Mail::SpamAssassin::Conf::CONF_TYPE_STRINGLIST) { | ||||
693 | $cmd->{code} = \&set_string_list; | ||||
694 | } | ||||
695 | elsif ($type == $Mail::SpamAssassin::Conf::CONF_TYPE_IPADDRLIST) { | ||||
696 | $cmd->{code} = \&set_ipaddr_list; | ||||
697 | } | ||||
698 | elsif ($type == $Mail::SpamAssassin::Conf::CONF_TYPE_DURATION) { | ||||
699 | $cmd->{code} = \&set_duration_value; | ||||
700 | } | ||||
701 | else { | ||||
702 | warn "config: unknown conf type $type!"; | ||||
703 | return 0; | ||||
704 | } | ||||
705 | 21 | 152µs | return 1; | ||
706 | } | ||||
707 | |||||
708 | sub set_no_value { | ||||
709 | my ($conf, $key, $value, $line) = @_; | ||||
710 | |||||
711 | unless (!defined $value || $value eq '') { | ||||
712 | return $Mail::SpamAssassin::Conf::INVALID_VALUE; | ||||
713 | } | ||||
714 | } | ||||
715 | |||||
716 | # spent 394µs (209+186) within Mail::SpamAssassin::Conf::Parser::set_numeric_value which was called 4 times, avg 99µs/call:
# 4 times (209µs+186µs) by Mail::SpamAssassin::Conf::Parser::parse at line 438, avg 99µs/call | ||||
717 | 4 | 35µs | my ($conf, $key, $value, $line) = @_; | ||
718 | |||||
719 | 4 | 39µs | 4 | 11µs | unless (defined $value && $value !~ /^$/) { # spent 11µs making 4 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 3µs/call |
720 | return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE; | ||||
721 | } | ||||
722 | 4 | 59µs | 4 | 31µs | unless ($value =~ /^ [+-]? \d+ (?: \. \d* )? \z/sx) { # spent 31µs making 4 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 8µs/call |
723 | return $Mail::SpamAssassin::Conf::INVALID_VALUE; | ||||
724 | } | ||||
725 | # it is safe to untaint now that we know the syntax is a valid number | ||||
726 | 4 | 77µs | 4 | 144µs | $conf->{$key} = untaint_var($value) + 0; # spent 144µs making 4 calls to Mail::SpamAssassin::Util::untaint_var, avg 36µs/call |
727 | } | ||||
728 | |||||
729 | sub set_duration_value { | ||||
730 | my ($conf, $key, $value, $line) = @_; | ||||
731 | |||||
732 | local ($1,$2); | ||||
733 | unless (defined $value && $value !~ /^$/) { | ||||
734 | return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE; | ||||
735 | } | ||||
736 | unless ($value =~ /^( \+? \d+ (?: \. \d* )? ) (?: \s* ([smhdw]))? \z/sxi) { | ||||
737 | return $Mail::SpamAssassin::Conf::INVALID_VALUE; | ||||
738 | } | ||||
739 | $value = $1; | ||||
740 | $value *= { s => 1, m => 60, h => 3600, | ||||
741 | d => 24*3600, w => 7*24*3600 }->{lc $2} if defined $2; | ||||
742 | # it is safe to untaint now that we know the syntax is a valid time interval | ||||
743 | $conf->{$key} = untaint_var($value) + 0; | ||||
744 | } | ||||
745 | |||||
746 | # spent 255µs (242+14) within Mail::SpamAssassin::Conf::Parser::set_bool_value which was called 5 times, avg 51µs/call:
# 5 times (242µs+14µs) by Mail::SpamAssassin::Conf::Parser::parse at line 438, avg 51µs/call | ||||
747 | 5 | 43µs | my ($conf, $key, $value, $line) = @_; | ||
748 | |||||
749 | 5 | 55µs | 5 | 14µs | unless (defined $value && $value !~ /^$/) { # spent 14µs making 5 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 3µs/call |
750 | return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE; | ||||
751 | } | ||||
752 | |||||
753 | # bug 4462: allow yes/1 and no/0 for boolean values | ||||
754 | 5 | 15µs | $value = lc $value; | ||
755 | 5 | 32µs | if ($value eq 'yes' || $value eq '1') { | ||
756 | 4 | 8µs | $value = 1; | ||
757 | } | ||||
758 | elsif ($value eq 'no' || $value eq '0') { | ||||
759 | 1 | 2µs | $value = 0; | ||
760 | } | ||||
761 | else { | ||||
762 | return $Mail::SpamAssassin::Conf::INVALID_VALUE; | ||||
763 | } | ||||
764 | |||||
765 | 5 | 67µs | $conf->{$key} = $value; | ||
766 | } | ||||
767 | |||||
768 | # spent 94µs (78+16) within Mail::SpamAssassin::Conf::Parser::set_string_value which was called 3 times, avg 31µs/call:
# 3 times (78µs+16µs) by Mail::SpamAssassin::Conf::Parser::parse at line 438, avg 31µs/call | ||||
769 | 3 | 17µs | my ($conf, $key, $value, $line) = @_; | ||
770 | |||||
771 | 3 | 38µs | 3 | 16µs | unless (defined $value && $value !~ /^$/) { # spent 16µs making 3 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 5µs/call |
772 | return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE; | ||||
773 | } | ||||
774 | |||||
775 | 3 | 37µs | $conf->{$key} = $value; # keep tainted | ||
776 | } | ||||
777 | |||||
778 | sub set_string_list { | ||||
779 | my ($conf, $key, $value, $line) = @_; | ||||
780 | |||||
781 | unless (defined $value && $value !~ /^$/) { | ||||
782 | return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE; | ||||
783 | } | ||||
784 | |||||
785 | push(@{$conf->{$key}}, split(' ', $value)); | ||||
786 | } | ||||
787 | |||||
788 | sub set_ipaddr_list { | ||||
789 | my ($conf, $key, $value, $line) = @_; | ||||
790 | |||||
791 | unless (defined $value && $value !~ /^$/) { | ||||
792 | return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE; | ||||
793 | } | ||||
794 | |||||
795 | foreach my $net (split(' ', $value)) { | ||||
796 | $conf->{$key}->add_cidr($net); | ||||
797 | } | ||||
798 | $conf->{$key.'_configured'} = 1; | ||||
799 | } | ||||
800 | |||||
801 | # spent 260ms (57.2+202) within Mail::SpamAssassin::Conf::Parser::set_hash_key_value which was called 1276 times, avg 203µs/call:
# 1276 times (57.2ms+202ms) by Mail::SpamAssassin::Conf::Parser::parse at line 438, avg 203µs/call | ||||
802 | 1276 | 6.70ms | my ($conf, $key, $value, $line) = @_; | ||
803 | 1276 | 8.54ms | my($k,$v) = split(/\s+/, $value, 2); | ||
804 | |||||
805 | 1276 | 2.71ms | unless (defined $v && $v ne '') { | ||
806 | return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE; | ||||
807 | } | ||||
808 | |||||
809 | 1276 | 30.7ms | 1684 | 202ms | $conf->{$key}->{$k} = $v; # keep tainted # spent 110ms making 842 calls to Mail::SpamAssassin::Util::TieOneStringHash::STORE, avg 130µs/call
# spent 92.6ms making 842 calls to Mail::SpamAssassin::Util::TieOneStringHash::FETCH, avg 110µs/call |
810 | } | ||||
811 | |||||
812 | # spent 4.60ms (885µs+3.72) within Mail::SpamAssassin::Conf::Parser::set_addrlist_value which was called 34 times, avg 135µs/call:
# 34 times (885µs+3.72ms) by Mail::SpamAssassin::Conf::Parser::parse at line 438, avg 135µs/call | ||||
813 | 34 | 166µs | my ($conf, $key, $value, $line) = @_; | ||
814 | |||||
815 | 34 | 303µs | 34 | 90µs | unless (defined $value && $value !~ /^$/) { # spent 90µs making 34 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 3µs/call |
816 | return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE; | ||||
817 | } | ||||
818 | 34 | 482µs | 34 | 3.63ms | $conf->{parser}->add_to_addrlist ($key, split (' ', $value)); # keep tainted # spent 3.63ms making 34 calls to Mail::SpamAssassin::Conf::Parser::add_to_addrlist, avg 107µs/call |
819 | } | ||||
820 | |||||
821 | sub remove_addrlist_value { | ||||
822 | my ($conf, $key, $value, $line) = @_; | ||||
823 | |||||
824 | unless (defined $value && $value !~ /^$/) { | ||||
825 | return $Mail::SpamAssassin::Conf::MISSING_REQUIRED_VALUE; | ||||
826 | } | ||||
827 | $conf->{parser}->remove_from_addrlist ($key, split (' ', $value)); | ||||
828 | } | ||||
829 | |||||
830 | # spent 542µs (494+48) within Mail::SpamAssassin::Conf::Parser::set_template_append which was called 17 times, avg 32µs/call:
# 17 times (494µs+48µs) by Mail::SpamAssassin::Conf::Parser::parse at line 438, avg 32µs/call | ||||
831 | 17 | 200µs | my ($conf, $key, $value, $line) = @_; | ||
832 | 18 | 153µs | 17 | 48µs | if ( $value =~ /^"(.*?)"$/ ) { $value = $1; } # spent 48µs making 17 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 3µs/call |
833 | 17 | 193µs | $conf->{$key} .= $value."\n"; # keep tainted | ||
834 | } | ||||
835 | |||||
836 | # spent 52µs within Mail::SpamAssassin::Conf::Parser::set_template_clear which was called 2 times, avg 26µs/call:
# 2 times (52µs+0s) by Mail::SpamAssassin::Conf::Parser::parse at line 438, avg 26µs/call | ||||
837 | 2 | 19µs | my ($conf, $key, $value, $line) = @_; | ||
838 | 2 | 5µs | unless (!defined $value || $value eq '') { | ||
839 | return $Mail::SpamAssassin::Conf::INVALID_VALUE; | ||||
840 | } | ||||
841 | 2 | 21µs | $conf->{$key} = ''; | ||
842 | } | ||||
843 | |||||
844 | ########################################################################### | ||||
845 | |||||
846 | # spent 6.01s (104ms+5.91) within Mail::SpamAssassin::Conf::Parser::finish_parsing which was called:
# once (104ms+5.91s) by Mail::SpamAssassin::Conf::finish_parsing at line 4860 of Mail/SpamAssassin/Conf.pm | ||||
847 | 1 | 2µs | my ($self, $isuserconf) = @_; | ||
848 | 1 | 3µs | my $conf = $self->{conf}; | ||
849 | |||||
850 | # note: this function is called once for system-wide configuration | ||||
851 | # with $isuserconf set to 0, then again for user conf with $isuserconf set to 1. | ||||
852 | 1 | 7µs | if (!$isuserconf) { | ||
853 | 1 | 15µs | 1 | 752µs | $conf->{main}->call_plugins("finish_parsing_start", { conf => $conf }); # spent 752µs making 1 call to Mail::SpamAssassin::call_plugins |
854 | } else { | ||||
855 | $conf->{main}->call_plugins("user_conf_parsing_start", { conf => $conf }); | ||||
856 | } | ||||
857 | |||||
858 | 1 | 373µs | 1 | 5.49s | $self->trace_meta_dependencies(); # spent 5.49s making 1 call to Mail::SpamAssassin::Conf::Parser::trace_meta_dependencies |
859 | 1 | 175µs | 1 | 111ms | $self->fix_priorities(); # spent 111ms making 1 call to Mail::SpamAssassin::Conf::Parser::fix_priorities |
860 | |||||
861 | # don't do this if allow_user_rules is active, since it deletes entries | ||||
862 | # from {tests} | ||||
863 | 1 | 12µs | if (!$conf->{allow_user_rules}) { | ||
864 | 1 | 13µs | 1 | 116ms | $self->find_dup_rules(); # must be after fix_priorities() # spent 116ms making 1 call to Mail::SpamAssassin::Conf::Parser::find_dup_rules |
865 | } | ||||
866 | |||||
867 | 1 | 8µs | 1 | 8µs | dbg("config: finish parsing"); # spent 8µs making 1 call to Mail::SpamAssassin::Logger::dbg |
868 | |||||
869 | 2058 | 33.8ms | while (my ($name, $text) = each %{$conf->{tests}}) { | ||
870 | 2056 | 4.10ms | my $type = $conf->{test_types}->{$name}; | ||
871 | 2056 | 5.16ms | my $priority = $conf->{priority}->{$name} || 0; | ||
872 | 2056 | 3.74ms | $conf->{priorities}->{$priority}++; | ||
873 | |||||
874 | # eval type handling | ||||
875 | 2056 | 6.52ms | if (($type & 1) == 1) { | ||
876 | 379 | 21.6ms | 379 | 4.62ms | if (my ($function, $args) = ($text =~ m/(.*?)\s*\((.*?)\)\s*$/)) { # spent 4.62ms making 379 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 12µs/call |
877 | 379 | 2.99ms | 379 | 47.1ms | my ($packed, $argsref) = # spent 47.1ms making 379 calls to Mail::SpamAssassin::Conf::Parser::pack_eval_method, avg 124µs/call |
878 | $self->pack_eval_method($function, $args, $name, $text); | ||||
879 | |||||
880 | 379 | 2.18ms | if (!$packed) { | ||
881 | # we've already warned about this | ||||
882 | } | ||||
883 | elsif ($type == $Mail::SpamAssassin::Conf::TYPE_BODY_EVALS) { | ||||
884 | 187 | 1.62ms | $conf->{body_evals}->{$priority}->{$name} = $packed; | ||
885 | } | ||||
886 | elsif ($type == $Mail::SpamAssassin::Conf::TYPE_HEAD_EVALS) { | ||||
887 | 101 | 894µs | $conf->{head_evals}->{$priority}->{$name} = $packed; | ||
888 | } | ||||
889 | elsif ($type == $Mail::SpamAssassin::Conf::TYPE_RBL_EVALS) { | ||||
890 | # We don't do priorities for $Mail::SpamAssassin::Conf::TYPE_RBL_EVALS | ||||
891 | # we also use the arrayref instead of the packed string | ||||
892 | 73 | 872µs | $conf->{rbl_evals}->{$name} = [ $function, @$argsref ]; | ||
893 | } | ||||
894 | elsif ($type == $Mail::SpamAssassin::Conf::TYPE_RAWBODY_EVALS) { | ||||
895 | 7 | 66µs | $conf->{rawbody_evals}->{$priority}->{$name} = $packed; | ||
896 | } | ||||
897 | elsif ($type == $Mail::SpamAssassin::Conf::TYPE_FULL_EVALS) { | ||||
898 | 11 | 94µs | $conf->{full_evals}->{$priority}->{$name} = $packed; | ||
899 | } | ||||
900 | #elsif ($type == $Mail::SpamAssassin::Conf::TYPE_URI_EVALS) { | ||||
901 | # $conf->{uri_evals}->{$priority}->{$name} = $packed; | ||||
902 | #} | ||||
903 | else { | ||||
904 | $self->lint_warn("unknown type $type for $name: $text", $name); | ||||
905 | } | ||||
906 | } | ||||
907 | else { | ||||
908 | $self->lint_warn("syntax error for eval function $name: $text", $name); | ||||
909 | } | ||||
910 | } | ||||
911 | # non-eval tests | ||||
912 | else { | ||||
913 | 1677 | 5.45ms | if ($type == $Mail::SpamAssassin::Conf::TYPE_BODY_TESTS) { | ||
914 | 513 | 4.60ms | $conf->{body_tests}->{$priority}->{$name} = $text; | ||
915 | } | ||||
916 | elsif ($type == $Mail::SpamAssassin::Conf::TYPE_HEAD_TESTS) { | ||||
917 | 595 | 5.17ms | $conf->{head_tests}->{$priority}->{$name} = $text; | ||
918 | } | ||||
919 | elsif ($type == $Mail::SpamAssassin::Conf::TYPE_META_TESTS) { | ||||
920 | 463 | 4.11ms | $conf->{meta_tests}->{$priority}->{$name} = $text; | ||
921 | } | ||||
922 | elsif ($type == $Mail::SpamAssassin::Conf::TYPE_URI_TESTS) { | ||||
923 | 69 | 592µs | $conf->{uri_tests}->{$priority}->{$name} = $text; | ||
924 | } | ||||
925 | elsif ($type == $Mail::SpamAssassin::Conf::TYPE_RAWBODY_TESTS) { | ||||
926 | 33 | 298µs | $conf->{rawbody_tests}->{$priority}->{$name} = $text; | ||
927 | } | ||||
928 | elsif ($type == $Mail::SpamAssassin::Conf::TYPE_FULL_TESTS) { | ||||
929 | 2 | 19µs | $conf->{full_tests}->{$priority}->{$name} = $text; | ||
930 | } | ||||
931 | elsif ($type == $Mail::SpamAssassin::Conf::TYPE_EMPTY_TESTS) { | ||||
932 | } | ||||
933 | else { | ||||
934 | $self->lint_warn("unknown type $type for $name: $text", $name); | ||||
935 | } | ||||
936 | } | ||||
937 | } | ||||
938 | |||||
939 | 1 | 9µs | 1 | 20µs | $self->lint_trusted_networks(); # spent 20µs making 1 call to Mail::SpamAssassin::Conf::Parser::lint_trusted_networks |
940 | |||||
941 | 1 | 5µs | if (!$isuserconf) { | ||
942 | 1 | 15µs | 1 | 134ms | $conf->{main}->call_plugins("finish_parsing_end", { conf => $conf }); # spent 134ms making 1 call to Mail::SpamAssassin::call_plugins |
943 | } else { | ||||
944 | $conf->{main}->call_plugins("user_conf_parsing_end", { conf => $conf }); | ||||
945 | } | ||||
946 | |||||
947 | 1 | 12µs | 1 | 24µs | $conf->found_any_rules(); # before we might delete {tests} # spent 24µs making 1 call to Mail::SpamAssassin::Conf::found_any_rules |
948 | |||||
949 | 1 | 22µs | if (!$conf->{allow_user_rules}) { | ||
950 | # free up stuff we no longer need | ||||
951 | 1 | 1.82ms | delete $conf->{tests}; | ||
952 | 1 | 526µs | delete $conf->{priority}; | ||
953 | #test_types are needed - see bug 5503 | ||||
954 | #delete $conf->{test_types}; | ||||
955 | } | ||||
956 | } | ||||
957 | |||||
958 | # spent 5.49s (31.3ms+5.46) within Mail::SpamAssassin::Conf::Parser::trace_meta_dependencies which was called:
# once (31.3ms+5.46s) by Mail::SpamAssassin::Conf::Parser::finish_parsing at line 858 | ||||
959 | 1 | 2µs | my ($self) = @_; | ||
960 | 1 | 3µs | my $conf = $self->{conf}; | ||
961 | 1 | 4µs | $conf->{meta_dependencies} = { }; | ||
962 | |||||
963 | 2 | 3.21ms | foreach my $name (keys %{$conf->{tests}}) { | ||
964 | 2067 | 9.45ms | next unless ($conf->{test_types}->{$name} | ||
965 | == $Mail::SpamAssassin::Conf::TYPE_META_TESTS); | ||||
966 | |||||
967 | 464 | 982µs | my $deps = [ ]; | ||
968 | 464 | 836µs | my $alreadydone = { }; | ||
969 | 464 | 3.02ms | 464 | 5.46s | $self->_meta_deps_recurse($conf, $name, $name, $deps, $alreadydone); # spent 5.46s making 464 calls to Mail::SpamAssassin::Conf::Parser::_meta_deps_recurse, avg 11.8ms/call |
970 | 928 | 13.2ms | $conf->{meta_dependencies}->{$name} = join (' ', @{$deps}); | ||
971 | } | ||||
972 | } | ||||
973 | |||||
974 | # spent 5.46s (4.00+1.46) within Mail::SpamAssassin::Conf::Parser::_meta_deps_recurse which was called 13832 times, avg 395µs/call:
# 13368 times (3.81s+-3.81s) by Mail::SpamAssassin::Conf::Parser::_meta_deps_recurse at line 1000, avg 0s/call
# 464 times (191ms+5.27s) by Mail::SpamAssassin::Conf::Parser::trace_meta_dependencies at line 969, avg 11.8ms/call | ||||
975 | 13832 | 28.2ms | my ($self, $conf, $toprule, $name, $deps, $alreadydone) = @_; | ||
976 | |||||
977 | # Only do each rule once per top-level meta; avoid infinite recursion | ||||
978 | 13832 | 46.5ms | return if $alreadydone->{$name}; | ||
979 | 11323 | 74.2ms | $alreadydone->{$name} = 1; | ||
980 | |||||
981 | # Obviously, don't trace empty or nonexistent rules | ||||
982 | 11323 | 52.3ms | my $rule = $conf->{tests}->{$name}; | ||
983 | 11323 | 19.0ms | return unless $rule; | ||
984 | |||||
985 | # Lex the rule into tokens using a rather simple RE method ... | ||||
986 | 11321 | 18.5ms | my $lexer = ARITH_EXPRESSION_LEXER; | ||
987 | 11321 | 796ms | 22642 | 519ms | my @tokens = ($rule =~ m/$lexer/g); # spent 479ms making 11321 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 42µs/call
# spent 40.4ms making 11321 calls to Mail::SpamAssassin::Conf::Parser::CORE:regcomp, avg 4µs/call |
988 | |||||
989 | # Go through each token in the meta rule | ||||
990 | 11321 | 21.7ms | my $conf_tests = $conf->{tests}; | ||
991 | 11321 | 586ms | foreach my $token (@tokens) { | ||
992 | # has to be an alpha+numeric token | ||||
993 | # next if $token =~ /^(?:\W+|[+-]?\d+(?:\.\d+)?)$/; | ||||
994 | 269448 | 2.75s | 269448 | 610ms | next if $token !~ /^[A-Za-z_][A-Za-z0-9_]*\z/s; # faster # spent 610ms making 269448 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 2µs/call |
995 | # and has to be a rule name | ||||
996 | 120401 | 440ms | next unless exists $conf_tests->{$token}; | ||
997 | |||||
998 | # add and recurse | ||||
999 | 26736 | 142ms | 13368 | 335ms | push(@{$deps}, untaint_var($token)); # spent 335ms making 13368 calls to Mail::SpamAssassin::Util::untaint_var, avg 25µs/call |
1000 | 13368 | 108ms | 13368 | 0s | $self->_meta_deps_recurse($conf, $toprule, $token, $deps, $alreadydone); # spent 11.0s making 13368 calls to Mail::SpamAssassin::Conf::Parser::_meta_deps_recurse, avg 825µs/call, recursion: max depth 7, sum of overlapping time 11.0s |
1001 | } | ||||
1002 | } | ||||
1003 | |||||
1004 | # spent 111ms (91.0+20.1) within Mail::SpamAssassin::Conf::Parser::fix_priorities which was called:
# once (91.0ms+20.1ms) by Mail::SpamAssassin::Conf::Parser::finish_parsing at line 859 | ||||
1005 | 1 | 2µs | my ($self) = @_; | ||
1006 | 1 | 4µs | my $conf = $self->{conf}; | ||
1007 | |||||
1008 | 1 | 2µs | die unless $conf->{meta_dependencies}; # order requirement | ||
1009 | 1 | 3µs | my $pri = $conf->{priority}; | ||
1010 | |||||
1011 | # sort into priority order, lowest first -- this way we ensure that if we | ||||
1012 | # rearrange the pri of a rule early on, we cannot accidentally increase its | ||||
1013 | # priority later. | ||||
1014 | 1 | 3.15ms | 1 | 20.1ms | foreach my $rule (sort { # spent 20.1ms making 1 call to Mail::SpamAssassin::Conf::Parser::CORE:sort |
1015 | 9783 | 20.1ms | $pri->{$a} <=> $pri->{$b} | ||
1016 | 1 | 2µs | } keys %{$pri}) | ||
1017 | { | ||||
1018 | # we only need to worry about meta rules -- they are the | ||||
1019 | # only type of rules which depend on other rules | ||||
1020 | 2067 | 8.04ms | my $deps = $conf->{meta_dependencies}->{$rule}; | ||
1021 | 2067 | 3.28ms | next unless (defined $deps); | ||
1022 | |||||
1023 | 464 | 1.03ms | my $basepri = $pri->{$rule}; | ||
1024 | 464 | 9.44ms | foreach my $dep (split ' ', $deps) { | ||
1025 | 13368 | 25.0ms | my $deppri = $pri->{$dep}; | ||
1026 | 13368 | 41.1ms | if ($deppri > $basepri) { | ||
1027 | dbg("rules: $rule (pri $basepri) requires $dep (pri $deppri): fixed"); | ||||
1028 | $pri->{$dep} = $basepri; | ||||
1029 | } | ||||
1030 | } | ||||
1031 | } | ||||
1032 | } | ||||
1033 | |||||
1034 | # spent 116ms (112+3.45) within Mail::SpamAssassin::Conf::Parser::find_dup_rules which was called:
# once (112ms+3.45ms) by Mail::SpamAssassin::Conf::Parser::finish_parsing at line 864 | ||||
1035 | 1 | 4µs | my ($self) = @_; | ||
1036 | 1 | 3µs | my $conf = $self->{conf}; | ||
1037 | |||||
1038 | 1 | 2µs | my %names_for_text; | ||
1039 | my %dups; | ||||
1040 | 2069 | 35.4ms | while (my ($name, $text) = each %{$conf->{tests}}) { | ||
1041 | 2067 | 4.30ms | my $type = $conf->{test_types}->{$name}; | ||
1042 | |||||
1043 | # skip eval and empty tests | ||||
1044 | 2067 | 3.80ms | next if ($type & 1) || | ||
1045 | ($type eq $Mail::SpamAssassin::Conf::TYPE_EMPTY_TESTS); | ||||
1046 | |||||
1047 | 3372 | 38.9ms | 1686 | 3.24ms | my $tf = ($conf->{tflags}->{$name}||''); $tf =~ s/\s+/ /gs; # spent 3.24ms making 1686 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 2µs/call |
1048 | # ensure similar, but differently-typed, rules are not marked as dups; | ||||
1049 | # take tflags into account too due to "tflags multiple" | ||||
1050 | 1686 | 5.00ms | $text = "$type\t$text\t$tf"; | ||
1051 | |||||
1052 | 1686 | 7.32ms | if (defined $names_for_text{$text}) { | ||
1053 | 11 | 90µs | $names_for_text{$text} .= " ".$name; | ||
1054 | 11 | 40µs | $dups{$text} = undef; # found (at least) one | ||
1055 | } else { | ||||
1056 | 1675 | 18.9ms | $names_for_text{$text} = $name; | ||
1057 | } | ||||
1058 | } | ||||
1059 | |||||
1060 | 1 | 914µs | foreach my $text (keys %dups) { | ||
1061 | 10 | 15µs | my $first; | ||
1062 | my $first_pri; | ||||
1063 | 22 | 257µs | 10 | 78µs | my @names = sort {$a cmp $b} split(' ', $names_for_text{$text}); # spent 78µs making 10 calls to Mail::SpamAssassin::Conf::Parser::CORE:sort, avg 8µs/call |
1064 | 10 | 41µs | foreach my $name (@names) { | ||
1065 | 21 | 184µs | my $priority = $conf->{priority}->{$name} || 0; | ||
1066 | |||||
1067 | 21 | 86µs | if (!defined $first || $priority < $first_pri) { | ||
1068 | 10 | 15µs | $first_pri = $priority; | ||
1069 | 10 | 23µs | $first = $name; | ||
1070 | } | ||||
1071 | } | ||||
1072 | # $first is now the earliest-occurring rule. mark others as dups | ||||
1073 | |||||
1074 | 10 | 15µs | my @dups; | ||
1075 | 10 | 46µs | foreach my $name (@names) { | ||
1076 | 21 | 36µs | next if $name eq $first; | ||
1077 | 11 | 46µs | push @dups, $name; | ||
1078 | 11 | 108µs | delete $conf->{tests}->{$name}; | ||
1079 | } | ||||
1080 | |||||
1081 | 10 | 173µs | 10 | 130µs | dbg("rules: $first merged duplicates: ".join(' ', @dups)); # spent 130µs making 10 calls to Mail::SpamAssassin::Logger::dbg, avg 13µs/call |
1082 | 10 | 132µs | $conf->{duplicate_rules}->{$first} = \@dups; | ||
1083 | } | ||||
1084 | } | ||||
1085 | |||||
1086 | # spent 47.1ms (39.4+7.66) within Mail::SpamAssassin::Conf::Parser::pack_eval_method which was called 379 times, avg 124µs/call:
# 379 times (39.4ms+7.66ms) by Mail::SpamAssassin::Conf::Parser::finish_parsing at line 877, avg 124µs/call | ||||
1087 | 379 | 3.54ms | my ($self, $function, $args, $name, $text) = @_; | ||
1088 | |||||
1089 | 379 | 583µs | my @args; | ||
1090 | 379 | 1.29ms | if (defined $args) { | ||
1091 | # bug 4419: Parse quoted strings, unquoted alphanumerics/floats, | ||||
1092 | # unquoted IPv4 and IPv6 addresses, and unquoted common domain names. | ||||
1093 | # s// is used so that we can determine whether or not we successfully | ||||
1094 | # parsed ALL arguments. | ||||
1095 | 379 | 1.51ms | local($1,$2,$3); | ||
1096 | 379 | 7.27ms | 379 | 3.08ms | while ($args =~ s/^\s* (?: (['"]) (.*?) \1 | ( [\d\.:A-Za-z-]+? ) ) # spent 3.08ms making 379 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 8µs/call |
1097 | \s* (?: , \s* | $ )//x) { | ||||
1098 | 483 | 9.23ms | 483 | 2.67ms | if (defined $2) { # spent 2.67ms making 483 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 6µs/call |
1099 | 474 | 3.15ms | push @args, $2; | ||
1100 | } | ||||
1101 | else { | ||||
1102 | 9 | 73µs | push @args, $3; | ||
1103 | } | ||||
1104 | } | ||||
1105 | } | ||||
1106 | |||||
1107 | 379 | 704µs | if ($args ne '') { | ||
1108 | $self->lint_warn("syntax error (unparsable argument: $args) for eval function: $name: $text", $name); | ||||
1109 | return; | ||||
1110 | } | ||||
1111 | |||||
1112 | 379 | 788µs | my $argstr = $function; | ||
1113 | 379 | 4.05ms | 379 | 898µs | $argstr =~ s/\s+//gs; # spent 898µs making 379 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 2µs/call |
1114 | |||||
1115 | 379 | 1.52ms | if (@args > 0) { | ||
1116 | $argstr .= ',' . join(', ', | ||||
1117 | 1704 | 10.8ms | 483 | 1.01ms | map { my $s = $_; $s =~ s/\#/[HASH]/gs; 'q#' . $s . '#' } @args); # spent 1.01ms making 483 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 2µs/call |
1118 | } | ||||
1119 | 379 | 3.90ms | return ($argstr, \@args); | ||
1120 | } | ||||
1121 | |||||
1122 | ########################################################################### | ||||
1123 | |||||
1124 | # spent 20µs within Mail::SpamAssassin::Conf::Parser::lint_trusted_networks which was called:
# once (20µs+0s) by Mail::SpamAssassin::Conf::Parser::finish_parsing at line 939 | ||||
1125 | 1 | 2µs | my ($self) = @_; | ||
1126 | 1 | 4µs | my $conf = $self->{conf}; | ||
1127 | |||||
1128 | # validate trusted_networks and internal_networks, bug 4760. | ||||
1129 | # check that all internal_networks are listed in trusted_networks | ||||
1130 | # too. do the same for msa_networks, but check msa_networks against | ||||
1131 | # internal_networks if trusted_networks aren't defined | ||||
1132 | |||||
1133 | 1 | 2µs | my ($nt, $matching_against); | ||
1134 | 1 | 4µs | if ($conf->{trusted_networks_configured}) { | ||
1135 | $nt = $conf->{trusted_networks}; | ||||
1136 | $matching_against = 'trusted_networks'; | ||||
1137 | } elsif ($conf->{internal_networks_configured}) { | ||||
1138 | $nt = $conf->{internal_networks}; | ||||
1139 | $matching_against = 'internal_networks'; | ||||
1140 | } else { | ||||
1141 | 1 | 16µs | return; | ||
1142 | } | ||||
1143 | |||||
1144 | foreach my $net_type ('internal_networks', 'msa_networks') { | ||||
1145 | next unless $conf->{"${net_type}_configured"}; | ||||
1146 | next if $net_type eq $matching_against; | ||||
1147 | |||||
1148 | my $replace_nets; | ||||
1149 | my @valid_net_list; | ||||
1150 | my $net_list = $conf->{$net_type}; | ||||
1151 | |||||
1152 | foreach my $net (@{$net_list->{nets}}) { | ||||
1153 | # don't check to see if an excluded network is included - that's senseless | ||||
1154 | if (!$net->{exclude} && !$nt->contains_net($net)) { | ||||
1155 | my $msg = "$matching_against doesn't contain $net_type entry '". | ||||
1156 | ($net->{as_string})."'"; | ||||
1157 | |||||
1158 | $self->lint_warn($msg, undef); # complain | ||||
1159 | $replace_nets = 1; # and omit it from the new internal set | ||||
1160 | } | ||||
1161 | else { | ||||
1162 | push @valid_net_list, $net; | ||||
1163 | } | ||||
1164 | } | ||||
1165 | |||||
1166 | if ($replace_nets) { | ||||
1167 | # something was invalid. replace the old nets list with a fixed version | ||||
1168 | # (which may be empty) | ||||
1169 | $net_list->{nets} = \@valid_net_list; | ||||
1170 | } | ||||
1171 | } | ||||
1172 | } | ||||
1173 | |||||
1174 | ########################################################################### | ||||
1175 | |||||
1176 | # spent 726ms (207+519) within Mail::SpamAssassin::Conf::Parser::add_test which was called 2074 times, avg 350µs/call:
# 548 times (70.6ms+118ms) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:2981] at line 2979 of Mail/SpamAssassin/Conf.pm, avg 344µs/call
# 513 times (43.4ms+144ms) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3020] at line 3018 of Mail/SpamAssassin/Conf.pm, avg 364µs/call
# 465 times (50.0ms+225ms) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3174] at line 3173 of Mail/SpamAssassin/Conf.pm, avg 592µs/call
# 142 times (10.4ms+909µs) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3020] at line 3011 of Mail/SpamAssassin/Conf.pm, avg 79µs/call
# 102 times (7.66ms+641µs) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:2981] at line 2958 of Mail/SpamAssassin/Conf.pm, avg 81µs/call
# 73 times (5.20ms+447µs) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:2981] at line 2955 of Mail/SpamAssassin/Conf.pm, avg 77µs/call
# 71 times (6.13ms+21.9ms) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3052] at line 3051 of Mail/SpamAssassin/Conf.pm, avg 395µs/call
# 58 times (4.93ms+717µs) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:2981] at line 2970 of Mail/SpamAssassin/Conf.pm, avg 97µs/call
# 46 times (3.49ms+318µs) by Mail::SpamAssassin::Plugin::MIMEHeader::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Plugin/MIMEHeader.pm:160] at line 140 of Mail/SpamAssassin/Plugin/MIMEHeader.pm, avg 83µs/call
# 33 times (3.45ms+7.01ms) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3088] at line 3086 of Mail/SpamAssassin/Conf.pm, avg 317µs/call
# 11 times (884µs+78µs) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3122] at line 3114 of Mail/SpamAssassin/Conf.pm, avg 87µs/call
# 7 times (495µs+79µs) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3088] at line 3080 of Mail/SpamAssassin/Conf.pm, avg 82µs/call
# 2 times (190µs+314µs) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3122] at line 3120 of Mail/SpamAssassin/Conf.pm, avg 252µs/call
# 2 times (121µs+13µs) by Mail::SpamAssassin::Plugin::AskDNS::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Plugin/AskDNS.pm:356] at line 353 of Mail/SpamAssassin/Plugin/AskDNS.pm, avg 67µs/call
# once (90µs+13µs) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:3206] at line 3204 of Mail/SpamAssassin/Conf.pm | ||||
1177 | 2074 | 9.88ms | my ($self, $name, $text, $type) = @_; | ||
1178 | 2074 | 4.45ms | my $conf = $self->{conf}; | ||
1179 | |||||
1180 | # Don't allow invalid names ... | ||||
1181 | 2074 | 29.5ms | 2074 | 7.72ms | if ($name !~ /^\D\w*$/) { # spent 7.72ms making 2074 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 4µs/call |
1182 | $self->lint_warn("config: error: rule '$name' has invalid characters ". | ||||
1183 | "(not Alphanumeric + Underscore + starting with a non-digit)\n", $name); | ||||
1184 | return; | ||||
1185 | } | ||||
1186 | |||||
1187 | # Also set a hard limit for ALL rules (rule names longer than 242 | ||||
1188 | # characters throw warnings). Check this separately from the above | ||||
1189 | # pattern to avoid vague error messages. | ||||
1190 | 2074 | 4.81ms | if (length $name > 200) { | ||
1191 | $self->lint_warn("config: error: rule '$name' is way too long ". | ||||
1192 | "(recommended maximum length is 22 characters)\n", $name); | ||||
1193 | return; | ||||
1194 | } | ||||
1195 | |||||
1196 | # Warn about, but use, long rule names during --lint | ||||
1197 | 2074 | 3.96ms | if ($conf->{lint_rules}) { | ||
1198 | if (length($name) > 50 && $name !~ /^__/ && $name !~ /^T_/) { | ||||
1199 | $self->lint_warn("config: warning: rule name '$name' is over 50 chars ". | ||||
1200 | "(recommended maximum length is 22 characters)\n", $name); | ||||
1201 | } | ||||
1202 | } | ||||
1203 | |||||
1204 | # all of these rule types are regexps | ||||
1205 | 2074 | 5.37ms | if ($type == $Mail::SpamAssassin::Conf::TYPE_BODY_TESTS || | ||
1206 | $type == $Mail::SpamAssassin::Conf::TYPE_FULL_TESTS || | ||||
1207 | $type == $Mail::SpamAssassin::Conf::TYPE_RAWBODY_TESTS || | ||||
1208 | $type == $Mail::SpamAssassin::Conf::TYPE_URI_TESTS) | ||||
1209 | { | ||||
1210 | 619 | 4.26ms | 619 | 169ms | return unless $self->is_delimited_regexp_valid($name, $text); # spent 169ms making 619 calls to Mail::SpamAssassin::Conf::Parser::is_delimited_regexp_valid, avg 273µs/call |
1211 | } | ||||
1212 | 2074 | 5.90ms | if ($type == $Mail::SpamAssassin::Conf::TYPE_HEAD_TESTS) | ||
1213 | { | ||||
1214 | # RFC 5322 section 3.6.8, ftext printable US-ASCII chars not including ":" | ||||
1215 | # no re "strict"; # since perl 5.21.8: Ranges of ASCII printables... | ||||
1216 | 606 | 6.90ms | 606 | 1.83ms | if ($text =~ /^!?defined\([!-9;-\176]+\)$/) { # spent 1.83ms making 606 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 3µs/call |
1217 | # fine, implements 'exists:' | ||||
1218 | } else { | ||||
1219 | 548 | 20.3ms | 548 | 7.66ms | my ($pat) = ($text =~ /^\s*\S+\s*(?:\=|\!)\~\s*(\S.*?\S)\s*$/); # spent 7.66ms making 548 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 14µs/call |
1220 | 1096 | 6.89ms | 548 | 1.51ms | if ($pat) { $pat =~ s/\s+\[if-unset:\s+(.+)\]\s*$//; } # spent 1.51ms making 548 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 3µs/call |
1221 | 548 | 3.94ms | 548 | 104ms | return unless $self->is_delimited_regexp_valid($name, $pat); # spent 104ms making 548 calls to Mail::SpamAssassin::Conf::Parser::is_delimited_regexp_valid, avg 190µs/call |
1222 | } | ||||
1223 | } | ||||
1224 | elsif ($type == $Mail::SpamAssassin::Conf::TYPE_META_TESTS) | ||||
1225 | { | ||||
1226 | 465 | 3.27ms | 465 | 222ms | return unless $self->is_meta_valid($name, $text); # spent 222ms making 465 calls to Mail::SpamAssassin::Conf::Parser::is_meta_valid, avg 477µs/call |
1227 | } | ||||
1228 | |||||
1229 | 2074 | 26.8ms | $conf->{tests}->{$name} = $text; | ||
1230 | 2074 | 9.36ms | $conf->{test_types}->{$name} = $type; | ||
1231 | |||||
1232 | 2074 | 18.7ms | 2074 | 5.46ms | if ($name =~ /AUTOLEARNTEST/i) { # spent 5.46ms making 2074 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 3µs/call |
1233 | dbg("config: auto-learn: $name has type $type = $conf->{test_types}->{$name} during add_test\n"); | ||||
1234 | } | ||||
1235 | |||||
1236 | |||||
1237 | 2074 | 7.18ms | if ($type == $Mail::SpamAssassin::Conf::TYPE_META_TESTS) { | ||
1238 | 465 | 3.67ms | $conf->{priority}->{$name} ||= 500; | ||
1239 | } | ||||
1240 | else { | ||||
1241 | 1609 | 12.0ms | $conf->{priority}->{$name} ||= 0; | ||
1242 | } | ||||
1243 | 2074 | 4.63ms | $conf->{priority}->{$name} ||= 0; | ||
1244 | 2074 | 18.8ms | $conf->{source_file}->{$name} = $self->{currentfile}; | ||
1245 | |||||
1246 | 2074 | 4.29ms | if ($conf->{main}->{keep_config_parsing_metadata}) { | ||
1247 | $conf->{if_stack}->{$name} = $self->get_if_stack_as_string(); | ||||
1248 | |||||
1249 | if ($self->{file_scoped_attrs}->{testrules}) { | ||||
1250 | $conf->{testrules}->{$name} = 1; # used in build/mkupdates/listpromotable | ||||
1251 | } | ||||
1252 | } | ||||
1253 | |||||
1254 | # if we found this rule in a user_prefs file, it's a user rule -- note that | ||||
1255 | # we may need to recompile the rule code for this type (if they've already | ||||
1256 | # been compiled, e.g. in spamd). | ||||
1257 | # | ||||
1258 | # Note: the want_rebuild_for_type 'flag' is actually a counter; it is decremented | ||||
1259 | # after each scan. This ensures that we always recompile at least once more; | ||||
1260 | # once to *define* the rule, and once afterwards to *undefine* the rule in the | ||||
1261 | # compiled ruleset again. | ||||
1262 | # | ||||
1263 | # If two consecutive scans use user rules, that's ok -- the second one will | ||||
1264 | # reset the counter, and we'll still recompile just once afterwards to undefine | ||||
1265 | # the rule again. | ||||
1266 | # | ||||
1267 | 2074 | 25.8ms | if ($self->{scoresonly}) { | ||
1268 | $conf->{want_rebuild_for_type}->{$type} = 2; | ||||
1269 | $conf->{user_defined_rules}->{$name} = 1; | ||||
1270 | } | ||||
1271 | } | ||||
1272 | |||||
1273 | sub add_regression_test { | ||||
1274 | my ($self, $name, $ok_or_fail, $string) = @_; | ||||
1275 | my $conf = $self->{conf}; | ||||
1276 | |||||
1277 | if ($conf->{regression_tests}->{$name}) { | ||||
1278 | push @{$conf->{regression_tests}->{$name}}, [$ok_or_fail, $string]; | ||||
1279 | } | ||||
1280 | else { | ||||
1281 | # initialize the array, and create one element | ||||
1282 | $conf->{regression_tests}->{$name} = [ [$ok_or_fail, $string] ]; | ||||
1283 | } | ||||
1284 | } | ||||
1285 | |||||
1286 | # spent 222ms (169+53.3) within Mail::SpamAssassin::Conf::Parser::is_meta_valid which was called 465 times, avg 477µs/call:
# 465 times (169ms+53.3ms) by Mail::SpamAssassin::Conf::Parser::add_test at line 1226, avg 477µs/call | ||||
1287 | 465 | 2.29ms | my ($self, $name, $rule) = @_; | ||
1288 | |||||
1289 | 465 | 997µs | my $meta = ''; | ||
1290 | 465 | 3.56ms | 465 | 12.7ms | $rule = untaint_var($rule); # must be careful below # spent 12.7ms making 465 calls to Mail::SpamAssassin::Util::untaint_var, avg 27µs/call |
1291 | |||||
1292 | # Lex the rule into tokens using a rather simple RE method ... | ||||
1293 | 465 | 961µs | my $lexer = ARITH_EXPRESSION_LEXER; | ||
1294 | 465 | 28.2ms | 930 | 18.8ms | my @tokens = ($rule =~ m/$lexer/g); # spent 16.5ms making 465 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 35µs/call
# spent 2.27ms making 465 calls to Mail::SpamAssassin::Conf::Parser::CORE:regcomp, avg 5µs/call |
1295 | 465 | 1.29ms | if (length($name) == 1) { | ||
1296 | for (@tokens) { | ||||
1297 | print "$name $_\n " or die "Error writing token: $!"; | ||||
1298 | } | ||||
1299 | } | ||||
1300 | # Go through each token in the meta rule | ||||
1301 | 465 | 1.85ms | foreach my $token (@tokens) { | ||
1302 | # Numbers can't be rule names | ||||
1303 | 7210 | 113ms | 7210 | 21.8ms | if ($token !~ /^[A-Za-z_][A-Za-z0-9_]*\z/s) { # spent 21.8ms making 7210 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 3µs/call |
1304 | 4112 | 7.84ms | $meta .= "$token "; | ||
1305 | } | ||||
1306 | # Zero will probably cause more errors | ||||
1307 | else { | ||||
1308 | 3098 | 5.59ms | $meta .= "0 "; | ||
1309 | } | ||||
1310 | } | ||||
1311 | |||||
1312 | 465 | 1.30ms | my $evalstr = 'my $x = ' . $meta . '; 1;'; | ||
1313 | 465 | 29.8ms | if (eval $evalstr) { # spent 502µs executing statements in 42 string evals (merged)
# spent 413µs executing statements in 37 string evals (merged)
# spent 304µs executing statements in 2 string evals (merged)
# spent 299µs executing statements in 24 string evals (merged)
# spent 284µs executing statements in 26 string evals (merged)
# spent 197µs executing statements in 17 string evals (merged)
# spent 185µs executing statements in 20 string evals (merged)
# spent 172µs executing statements in 14 string evals (merged)
# spent 134µs executing statements in 12 string evals (merged)
# spent 116µs executing statements in 8 string evals (merged)
# spent 104µs executing statements in 8 string evals (merged)
# spent 96µs executing statements in 6 string evals (merged)
# spent 85µs executing statements in 6 string evals (merged)
# spent 82µs executing statements in 5 string evals (merged)
# spent 80µs executing statements in 8 string evals (merged)
# spent 78µs executing statements in 8 string evals (merged)
# spent 74µs executing statements in 5 string evals (merged)
# spent 72µs executing statements in 7 string evals (merged)
# spent 72µs executing statements in 7 string evals (merged)
# spent 71µs executing statements in 5 string evals (merged)
# spent 70µs executing statements in 6 string evals (merged)
# spent 66µs executing statements in 5 string evals (merged)
# spent 57µs executing statements in 6 string evals (merged)
# spent 57µs executing statements in 4 string evals (merged)
# spent 49µs executing statements in 3 string evals (merged)
# spent 45µs executing statements in 4 string evals (merged)
# spent 43µs executing statements in 3 string evals (merged)
# spent 40µs executing statements in 3 string evals (merged)
# spent 39µs executing statements in 3 string evals (merged)
# spent 38µs executing statements in 3 string evals (merged)
# spent 37µs executing statements in 4 string evals (merged)
# spent 37µs executing statements in 3 string evals (merged)
# spent 37µs executing statements in 3 string evals (merged)
# spent 33µs executing statements in 2 string evals (merged)
# spent 31µs executing statements in 2 string evals (merged)
# spent 31µs executing statements in 2 string evals (merged)
# spent 30µs executing statements in 2 string evals (merged)
# spent 29µs executing statements in 3 string evals (merged)
# spent 29µs executing statements in 2 string evals (merged)
# spent 28µs executing statements in 2 string evals (merged)
# spent 28µs executing statements in 2 string evals (merged)
# spent 28µs executing statements in 2 string evals (merged)
# spent 27µs executing statements in 2 string evals (merged)
# spent 26µs executing statements in 2 string evals (merged)
# spent 25µs executing statements in string eval
# spent 25µs executing statements in string eval
# spent 25µs executing statements in 2 string evals (merged)
# spent 24µs executing statements in 2 string evals (merged)
# spent 24µs executing statements in 2 string evals (merged)
# spent 23µs executing statements in 2 string evals (merged)
# spent 23µs executing statements in 2 string evals (merged)
# spent 23µs executing statements in 3 string evals (merged)
# spent 23µs executing statements in string eval
# spent 22µs executing statements in 2 string evals (merged)
# spent 21µs executing statements in 2 string evals (merged)
# spent 20µs executing statements in 2 string evals (merged)
# spent 20µs executing statements in string eval
# spent 20µs executing statements in string eval
# spent 20µs executing statements in 2 string evals (merged)
# spent 20µs executing statements in string eval
# spent 18µs executing statements in 2 string evals (merged)
# spent 17µs executing statements in 2 string evals (merged)
# spent 17µs executing statements in string eval
# spent 16µs executing statements in string eval
# spent 16µs executing statements in string eval
# spent 16µs executing statements in string eval
# spent 16µs executing statements in string eval
# spent 16µs executing statements in string eval
# spent 16µs executing statements in string eval
# spent 16µs executing statements in string eval
# spent 16µs executing statements in string eval
# spent 16µs executing statements in string eval
# spent 16µs executing statements in string eval
# spent 16µs executing statements in string eval
# spent 16µs executing statements in string eval
# spent 16µs executing statements in string eval
# spent 16µs executing statements in string eval
# spent 16µs executing statements in string eval
# spent 15µs executing statements in string eval
# spent 15µs executing statements in string eval
# spent 15µs executing statements in string eval
# spent 15µs executing statements in string eval
# spent 15µs executing statements in 2 string evals (merged)
# spent 15µs executing statements in 2 string evals (merged)
# spent 15µs executing statements in string eval
# spent 15µs executing statements in string eval
# spent 15µs executing statements in 2 string evals (merged)
# spent 14µs executing statements in string eval
# spent 14µs executing statements in string eval
# spent 14µs executing statements in string eval
# spent 14µs executing statements in string eval
# spent 14µs executing statements in string eval
# spent 14µs executing statements in string eval
# spent 14µs executing statements in string eval
# spent 14µs executing statements in string eval
# spent 14µs executing statements in string eval
# spent 14µs executing statements in string eval
# spent 14µs executing statements in string eval
# spent 13µs executing statements in string eval
# spent 13µs executing statements in string eval
# spent 13µs executing statements in string eval
# spent 13µs executing statements in string eval
# spent 13µs executing statements in string eval
# spent 13µs executing statements in string eval
# spent 12µs executing statements in string eval
# spent 12µs executing statements in string eval
# spent 12µs executing statements in string eval
# spent 12µs executing statements in string eval
# spent 12µs executing statements in string eval
# spent 12µs executing statements in string eval
# spent 12µs executing statements in string eval
# spent 11µs executing statements in string eval
# spent 11µs executing statements in string eval
# spent 11µs executing statements in string eval
# spent 11µs executing statements in string eval
# spent 10µs executing statements in string eval
# spent 10µs executing statements in string eval
# spent 10µs executing statements in string eval
# spent 10µs executing statements in string eval
# spent 9µs executing statements in string eval
# spent 9µs executing statements in string eval
# spent 9µs executing statements in string eval
# spent 9µs executing statements in string eval
# spent 9µs executing statements in string eval
# spent 9µs executing statements in string eval
# spent 8µs executing statements in string eval
# spent 8µs executing statements in string eval
# spent 8µs executing statements in string eval
# spent 8µs executing statements in string eval
# spent 8µs executing statements in string eval
# spent 8µs executing statements in string eval
# spent 8µs executing statements in string eval
# spent 8µs executing statements in string eval
# spent 8µs executing statements in string eval
# spent 8µs executing statements in string eval
# spent 8µs executing statements in string eval
# spent 8µs executing statements in string eval
# spent 8µs executing statements in string eval
# spent 8µs executing statements in string eval
# spent 8µs executing statements in string eval
# spent 8µs executing statements in string eval
# spent 7µs executing statements in string eval
# spent 7µs executing statements in string eval
# spent 7µs executing statements in string eval
# spent 7µs executing statements in string eval
# spent 7µs executing statements in string eval
# spent 7µs executing statements in string eval
# spent 7µs executing statements in string eval
# spent 7µs executing statements in string eval
# spent 7µs executing statements in string eval
# spent 7µs executing statements in string eval
# spent 7µs executing statements in string eval
# spent 7µs executing statements in string eval | ||
1314 | 465 | 6.33ms | return 1; | ||
1315 | } | ||||
1316 | my $err = $@ ne '' ? $@ : "errno=$!"; chomp $err; | ||||
1317 | $err =~ s/\s+(?:at|near)\b.*//s; | ||||
1318 | $err =~ s/Illegal division by zero/division by zero possible/i; | ||||
1319 | $self->lint_warn("config: invalid expression for rule $name: \"$rule\": $err\n", $name); | ||||
1320 | return 0; | ||||
1321 | } | ||||
1322 | |||||
1323 | # spent 285ms (46.2+238) within Mail::SpamAssassin::Conf::Parser::is_delimited_regexp_valid which was called 1228 times, avg 232µs/call:
# 619 times (31.3ms+138ms) by Mail::SpamAssassin::Conf::Parser::add_test at line 1210, avg 273µs/call
# 548 times (13.4ms+90.7ms) by Mail::SpamAssassin::Conf::Parser::add_test at line 1221, avg 190µs/call
# 46 times (1.12ms+7.47ms) by Mail::SpamAssassin::Plugin::MIMEHeader::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Plugin/MIMEHeader.pm:160] at line 116 of Mail/SpamAssassin/Plugin/MIMEHeader.pm, avg 187µs/call
# 15 times (380µs+2.63ms) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:2701] at line 2685 of Mail/SpamAssassin/Conf.pm, avg 201µs/call | ||||
1324 | 1228 | 6.15ms | my ($self, $name, $re) = @_; | ||
1325 | |||||
1326 | 1228 | 23.3ms | 1228 | 7.36ms | if (!$re || $re !~ /^\s*m?(\W).*(?:\1|>|}|\)|\])[a-z]*\s*$/) { # spent 7.36ms making 1228 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 6µs/call |
1327 | $re ||= ''; | ||||
1328 | $self->lint_warn("config: invalid regexp for rule $name: $re: missing or invalid delimiters\n", $name); | ||||
1329 | return 0; | ||||
1330 | } | ||||
1331 | 1228 | 15.1ms | 1228 | 231ms | return $self->is_regexp_valid($name, $re); # spent 231ms making 1228 calls to Mail::SpamAssassin::Conf::Parser::is_regexp_valid, avg 188µs/call |
1332 | } | ||||
1333 | |||||
1334 | # spent 231ms (123+108) within Mail::SpamAssassin::Conf::Parser::is_regexp_valid which was called 1228 times, avg 188µs/call:
# 1228 times (123ms+108ms) by Mail::SpamAssassin::Conf::Parser::is_delimited_regexp_valid at line 1331, avg 188µs/call | ||||
1335 | 1228 | 5.97ms | my ($self, $name, $re) = @_; | ||
1336 | |||||
1337 | # OK, try to remove any normal perl-style regexp delimiters at | ||||
1338 | # the start and end, and modifiers at the end if present, | ||||
1339 | # so we can validate those too. | ||||
1340 | 1228 | 2.83ms | my $origre = $re; | ||
1341 | 1228 | 2.77ms | my $safere = $re; | ||
1342 | 1228 | 2.34ms | my $mods = ''; | ||
1343 | 1228 | 4.45ms | local ($1,$2); | ||
1344 | 1228 | 63.1ms | 6034 | 19.4ms | if ($re =~ s/^m\{//) { # spent 19.4ms making 6034 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 3µs/call |
1345 | 28 | 269µs | 14 | 113µs | $re =~ s/\}([a-z]*)\z//; $mods = $1; # spent 113µs making 14 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 8µs/call |
1346 | } | ||||
1347 | elsif ($re =~ s/^m\(//) { | ||||
1348 | $re =~ s/\)([a-z]*)\z//; $mods = $1; | ||||
1349 | } | ||||
1350 | elsif ($re =~ s/^m<//) { | ||||
1351 | $re =~ s/>([a-z]*)\z//; $mods = $1; | ||||
1352 | } | ||||
1353 | elsif ($re =~ s/^m(\W)//) { | ||||
1354 | 100 | 2.20ms | 100 | 1.19ms | $re =~ s/\Q$1\E([a-z]*)\z//; $mods = $1; # spent 780µs making 50 calls to Mail::SpamAssassin::Conf::Parser::CORE:regcomp, avg 16µs/call
# spent 413µs making 50 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 8µs/call |
1355 | } | ||||
1356 | elsif ($re =~ s{^/(.*)/([a-z]*)\z}{$1}) { | ||||
1357 | 1164 | 3.62ms | $mods = $2; | ||
1358 | } | ||||
1359 | else { | ||||
1360 | $safere = "m#".$re."#"; | ||||
1361 | } | ||||
1362 | |||||
1363 | 1228 | 3.18ms | if ($self->{conf}->{lint_rules} || | ||
1364 | $self->{conf}->{ignore_always_matching_regexps}) | ||||
1365 | { | ||||
1366 | my $msg = $self->is_always_matching_regexp($name, $re); | ||||
1367 | |||||
1368 | if (defined $msg) { | ||||
1369 | if ($self->{conf}->{lint_rules}) { | ||||
1370 | $self->lint_warn($msg, $name); | ||||
1371 | } else { | ||||
1372 | warn $msg; | ||||
1373 | return 0; | ||||
1374 | } | ||||
1375 | } | ||||
1376 | } | ||||
1377 | |||||
1378 | # now prepend the modifiers, in order to check if they're valid | ||||
1379 | 1228 | 3.53ms | if ($mods) { | ||
1380 | 788 | 3.55ms | $re = "(?" . $mods . ")" . $re; | ||
1381 | } | ||||
1382 | |||||
1383 | # note: this MUST use m/...${re}.../ in some form or another, ie. | ||||
1384 | # interpolation of the $re variable into a code regexp, in order to test the | ||||
1385 | # security of the regexp. simply using ("" =~ $re) will NOT do that, and | ||||
1386 | # will therefore open a hole! | ||||
1387 | { # no re "strict"; # since perl 5.21.8: Ranges of ASCII printables... | ||||
1388 | 6140 | 145ms | 2456 | 87.1ms | if (eval { ("" =~ m{$re}); 1; }) { return 1 } # spent 84.7ms making 1228 calls to Mail::SpamAssassin::Conf::Parser::CORE:regcomp, avg 69µs/call
# spent 2.35ms making 1228 calls to Mail::SpamAssassin::Conf::Parser::CORE:match, avg 2µs/call |
1389 | } | ||||
1390 | my $err = $@ ne '' ? $@ : "errno=$!"; chomp $err; | ||||
1391 | $err =~ s/ at .*? line \d.*$//; | ||||
1392 | $self->lint_warn("config: invalid regexp for rule $name: $origre: $err\n", $name); | ||||
1393 | return 0; | ||||
1394 | } | ||||
1395 | |||||
1396 | # check the pattern for some basic errors, and warn if found | ||||
1397 | sub is_always_matching_regexp { | ||||
1398 | my ($self, $name, $re) = @_; | ||||
1399 | |||||
1400 | if ($re =~ /(?<!\\)\|\|/) { | ||||
1401 | return "config: regexp for rule $name always matches due to '||'"; | ||||
1402 | } | ||||
1403 | elsif ($re =~ /^\|/) { | ||||
1404 | return "config: regexp for rule $name always matches due to " . | ||||
1405 | "pattern starting with '|'"; | ||||
1406 | } | ||||
1407 | elsif ($re =~ /\|(?<!\\\|)$/) { | ||||
1408 | return "config: regexp for rule $name always matches due to " . | ||||
1409 | "pattern ending with '|'"; | ||||
1410 | } | ||||
1411 | return; | ||||
1412 | } | ||||
1413 | |||||
1414 | ########################################################################### | ||||
1415 | |||||
1416 | # spent 3.63ms (2.73+896µs) within Mail::SpamAssassin::Conf::Parser::add_to_addrlist which was called 34 times, avg 107µs/call:
# 34 times (2.73ms+896µs) by Mail::SpamAssassin::Conf::Parser::set_addrlist_value at line 818, avg 107µs/call | ||||
1417 | 34 | 148µs | my ($self, $singlelist, @addrs) = @_; | ||
1418 | 34 | 67µs | my $conf = $self->{conf}; | ||
1419 | |||||
1420 | 34 | 323µs | foreach my $addr (@addrs) { | ||
1421 | 34 | 102µs | $addr = lc $addr; | ||
1422 | 34 | 71µs | my $re = $addr; | ||
1423 | 34 | 290µs | 34 | 84µs | $re =~ s/[\000\\\(]/_/gs; # paranoia # spent 84µs making 34 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 2µs/call |
1424 | 34 | 1.54ms | 152 | 574µs | $re =~ s/([^\*\?_a-zA-Z0-9])/\\$1/g; # escape any possible metachars # spent 424µs making 118 calls to Mail::SpamAssassin::Conf::Parser::CORE:substcont, avg 4µs/call
# spent 150µs making 34 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 4µs/call |
1425 | 34 | 103µs | $re =~ tr/?/./; # "?" -> "." | ||
1426 | 34 | 507µs | 34 | 239µs | $re =~ s/\*+/\.\*/g; # "*" -> "any string" # spent 239µs making 34 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 7µs/call |
1427 | 34 | 537µs | $conf->{$singlelist}->{$addr} = "^${re}\$"; | ||
1428 | } | ||||
1429 | } | ||||
1430 | |||||
1431 | # spent 10.4ms (7.71+2.64) within Mail::SpamAssassin::Conf::Parser::add_to_addrlist_rcvd which was called 102 times, avg 101µs/call:
# 83 times (6.12ms+2.15ms) by Mail::SpamAssassin::Conf::Parser::add_to_addrlist_dkim at line 1470, avg 100µs/call
# 19 times (1.59ms+483µs) by Mail::SpamAssassin::Conf::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Conf.pm:433] at line 431 of Mail/SpamAssassin/Conf.pm, avg 109µs/call | ||||
1432 | 102 | 379µs | my ($self, $listname, $addr, $domain) = @_; | ||
1433 | 102 | 194µs | my $conf = $self->{conf}; | ||
1434 | |||||
1435 | 102 | 231µs | $domain = lc $domain; | ||
1436 | 102 | 229µs | $addr = lc $addr; | ||
1437 | 102 | 964µs | if ($conf->{$listname}->{$addr}) { | ||
1438 | 10 | 43µs | push @{$conf->{$listname}->{$addr}{domain}}, $domain; | ||
1439 | } | ||||
1440 | else { | ||||
1441 | 97 | 202µs | my $re = $addr; | ||
1442 | 97 | 789µs | 97 | 235µs | $re =~ s/[\000\\\(]/_/gs; # paranoia # spent 235µs making 97 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 2µs/call |
1443 | 97 | 4.00ms | 458 | 1.67ms | $re =~ s/([^\*\?_a-zA-Z0-9])/\\$1/g; # escape any possible metachars # spent 1.25ms making 361 calls to Mail::SpamAssassin::Conf::Parser::CORE:substcont, avg 3µs/call
# spent 418µs making 97 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 4µs/call |
1444 | 97 | 269µs | $re =~ tr/?/./; # "?" -> "." | ||
1445 | 97 | 1.34ms | 97 | 736µs | $re =~ s/\*+/\.\*/g; # "*" -> "any string" # spent 736µs making 97 calls to Mail::SpamAssassin::Conf::Parser::CORE:subst, avg 8µs/call |
1446 | 97 | 1.41ms | $conf->{$listname}->{$addr}{re} = "^${re}\$"; | ||
1447 | 97 | 532µs | $conf->{$listname}->{$addr}{domain} = [ $domain ]; | ||
1448 | } | ||||
1449 | } | ||||
1450 | |||||
1451 | sub remove_from_addrlist { | ||||
1452 | my ($self, $singlelist, @addrs) = @_; | ||||
1453 | my $conf = $self->{conf}; | ||||
1454 | |||||
1455 | foreach my $addr (@addrs) { | ||||
1456 | delete($conf->{$singlelist}->{lc $addr}); | ||||
1457 | } | ||||
1458 | } | ||||
1459 | |||||
1460 | sub remove_from_addrlist_rcvd { | ||||
1461 | my ($self, $listname, @addrs) = @_; | ||||
1462 | my $conf = $self->{conf}; | ||||
1463 | |||||
1464 | foreach my $addr (@addrs) { | ||||
1465 | delete($conf->{$listname}->{lc $addr}); | ||||
1466 | } | ||||
1467 | } | ||||
1468 | |||||
1469 | # spent 9.26ms (980µs+8.28) within Mail::SpamAssassin::Conf::Parser::add_to_addrlist_dkim which was called 83 times, avg 112µs/call:
# 83 times (980µs+8.28ms) by Mail::SpamAssassin::Plugin::DKIM::__ANON__[/usr/local/lib/perl5/site_perl/Mail/SpamAssassin/Plugin/DKIM.pm:420] at line 418 of Mail/SpamAssassin/Plugin/DKIM.pm, avg 112µs/call | ||||
1470 | 83 | 7.90ms | 83 | 8.28ms | add_to_addrlist_rcvd(@_); # spent 8.28ms making 83 calls to Mail::SpamAssassin::Conf::Parser::add_to_addrlist_rcvd, avg 100µs/call |
1471 | } | ||||
1472 | |||||
1473 | sub remove_from_addrlist_dkim { | ||||
1474 | my ($self, $listname, $addr, $domain) = @_; | ||||
1475 | my $conf = $self->{conf}; | ||||
1476 | my $conf_lname = $conf->{$listname}; | ||||
1477 | |||||
1478 | $addr = lc $addr; | ||||
1479 | if ($conf_lname->{$addr}) { | ||||
1480 | $domain = lc $domain; | ||||
1481 | my $domains_listref = $conf_lname->{$addr}{domain}; | ||||
1482 | # removing $domain from the list | ||||
1483 | my @replacement = grep { lc $_ ne $domain } @$domains_listref; | ||||
1484 | if (!@replacement) { # nothing left, remove the entire addr entry | ||||
1485 | delete($conf_lname->{$addr}); | ||||
1486 | } elsif (@replacement != @$domains_listref) { # anything changed? | ||||
1487 | $conf_lname->{$addr}{domain} = \@replacement; | ||||
1488 | } | ||||
1489 | } | ||||
1490 | } | ||||
1491 | |||||
1492 | |||||
1493 | ########################################################################### | ||||
1494 | |||||
1495 | # spent 23.2ms (4.67+18.6) within Mail::SpamAssassin::Conf::Parser::fix_path_relative_to_current_file which was called 58 times, avg 400µs/call:
# 58 times (4.67ms+18.6ms) by Mail::SpamAssassin::Conf::Parser::parse at line 342, avg 400µs/call | ||||
1496 | 58 | 246µs | my ($self, $path) = @_; | ||
1497 | |||||
1498 | # the path may be specified as "~/foo", so deal with that | ||||
1499 | 58 | 663µs | 58 | 13.1ms | $path = $self->{conf}->{main}->sed_path($path); # spent 13.1ms making 58 calls to Mail::SpamAssassin::sed_path, avg 225µs/call |
1500 | |||||
1501 | 58 | 982µs | 58 | 1.05ms | if (!File::Spec->file_name_is_absolute ($path)) { # spent 1.05ms making 58 calls to File::Spec::Unix::file_name_is_absolute, avg 18µs/call |
1502 | 58 | 680µs | 58 | 2.59ms | my ($vol, $dirs, $file) = File::Spec->splitpath ($self->{currentfile}); # spent 2.59ms making 58 calls to File::Spec::Unix::splitpath, avg 45µs/call |
1503 | 58 | 588µs | 58 | 1.21ms | $path = File::Spec->catpath ($vol, $dirs, $path); # spent 1.21ms making 58 calls to File::Spec::Unix::catpath, avg 21µs/call |
1504 | 58 | 636µs | 58 | 633µs | dbg("config: fixed relative path: $path"); # spent 633µs making 58 calls to Mail::SpamAssassin::Logger::dbg, avg 11µs/call |
1505 | } | ||||
1506 | 58 | 563µs | return $path; | ||
1507 | } | ||||
1508 | |||||
1509 | ########################################################################### | ||||
1510 | |||||
1511 | sub lint_warn { | ||||
1512 | my ($self, $msg, $rule, $iserror) = @_; | ||||
1513 | |||||
1514 | if (!defined $iserror) { $iserror = 1; } | ||||
1515 | |||||
1516 | if ($self->{conf}->{main}->{lint_callback}) { | ||||
1517 | $self->{conf}->{main}->{lint_callback}->( | ||||
1518 | msg => $msg, | ||||
1519 | rule => $rule, | ||||
1520 | iserror => $iserror | ||||
1521 | ); | ||||
1522 | } | ||||
1523 | elsif ($self->{conf}->{lint_rules}) { | ||||
1524 | warn $msg."\n"; | ||||
1525 | } | ||||
1526 | else { | ||||
1527 | info($msg); | ||||
1528 | } | ||||
1529 | |||||
1530 | if ($iserror) { | ||||
1531 | $self->{conf}->{errors}++; | ||||
1532 | } | ||||
1533 | } | ||||
1534 | |||||
1535 | ########################################################################### | ||||
1536 | |||||
1537 | sub get_if_stack_as_string { | ||||
1538 | my ($self) = @_; | ||||
1539 | return join ' ', map { | ||||
1540 | $_->{conditional} | ||||
1541 | } @{$self->{if_stack}}; | ||||
1542 | } | ||||
1543 | |||||
1544 | ########################################################################### | ||||
1545 | |||||
1546 | 1 | 12µs | 1; | ||
# spent 1.24s within Mail::SpamAssassin::Conf::Parser::CORE:match which was called 322611 times, avg 4µs/call:
# 269448 times (610ms+0s) by Mail::SpamAssassin::Conf::Parser::_meta_deps_recurse at line 994, avg 2µs/call
# 16436 times (44.9ms+0s) by Mail::SpamAssassin::Conf::Parser::parse at line 273, avg 3µs/call
# 11321 times (479ms+0s) by Mail::SpamAssassin::Conf::Parser::_meta_deps_recurse at line 987, avg 42µs/call
# 7210 times (21.8ms+0s) by Mail::SpamAssassin::Conf::Parser::is_meta_valid at line 1303, avg 3µs/call
# 2650 times (10.6ms+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 516, avg 4µs/call
# 2074 times (7.72ms+0s) by Mail::SpamAssassin::Conf::Parser::add_test at line 1181, avg 4µs/call
# 2074 times (5.46ms+0s) by Mail::SpamAssassin::Conf::Parser::add_test at line 1232, avg 3µs/call
# 2067 times (6.61ms+0s) by Mail::SpamAssassin::Conf::Parser::check_for_missing_descriptions at line 657, avg 3µs/call
# 1474 times (3.60ms+0s) by Mail::SpamAssassin::Conf::Parser::parse at line 286, avg 2µs/call
# 1284 times (2.48ms+0s) by Mail::SpamAssassin::Conf::Parser::set_default_scores at line 640, avg 2µs/call
# 1284 times (2.10ms+0s) by Mail::SpamAssassin::Conf::Parser::set_default_scores at line 642, avg 2µs/call
# 1228 times (7.36ms+0s) by Mail::SpamAssassin::Conf::Parser::is_delimited_regexp_valid at line 1326, avg 6µs/call
# 1228 times (2.35ms+0s) by Mail::SpamAssassin::Conf::Parser::is_regexp_valid at line 1388, avg 2µs/call
# 606 times (1.83ms+0s) by Mail::SpamAssassin::Conf::Parser::add_test at line 1216, avg 3µs/call
# 548 times (7.66ms+0s) by Mail::SpamAssassin::Conf::Parser::add_test at line 1219, avg 14µs/call
# 508 times (7.34ms+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 511, avg 14µs/call
# 465 times (16.5ms+0s) by Mail::SpamAssassin::Conf::Parser::is_meta_valid at line 1294, avg 35µs/call
# 379 times (4.62ms+0s) by Mail::SpamAssassin::Conf::Parser::finish_parsing at line 876, avg 12µs/call
# 136 times (734µs+0s) by Mail::SpamAssassin::Conf::Parser::parse at line 302, avg 5µs/call
# 68 times (382µs+0s) by Mail::SpamAssassin::Conf::Parser::parse at line 308, avg 6µs/call
# 55 times (461µs+0s) by Mail::SpamAssassin::Conf::Parser::cond_clause_can_or_has at line 588, avg 8µs/call
# 34 times (90µs+0s) by Mail::SpamAssassin::Conf::Parser::set_addrlist_value at line 815, avg 3µs/call
# 17 times (48µs+0s) by Mail::SpamAssassin::Conf::Parser::set_template_append at line 832, avg 3µs/call
# 5 times (14µs+0s) by Mail::SpamAssassin::Conf::Parser::set_bool_value at line 749, avg 3µs/call
# 4 times (31µs+0s) by Mail::SpamAssassin::Conf::Parser::set_numeric_value at line 722, avg 8µs/call
# 4 times (11µs+0s) by Mail::SpamAssassin::Conf::Parser::set_numeric_value at line 719, avg 3µs/call
# 3 times (16µs+0s) by Mail::SpamAssassin::Conf::Parser::set_string_value at line 771, avg 5µs/call
# once (8µs+0s) by Mail::SpamAssassin::Conf::Parser::parse at line 240 | |||||
# spent 137ms within Mail::SpamAssassin::Conf::Parser::CORE:regcomp which was called 15046 times, avg 9µs/call:
# 11321 times (40.4ms+0s) by Mail::SpamAssassin::Conf::Parser::_meta_deps_recurse at line 987, avg 4µs/call
# 1474 times (6.07ms+0s) by Mail::SpamAssassin::Conf::Parser::parse at line 286, avg 4µs/call
# 1228 times (84.7ms+0s) by Mail::SpamAssassin::Conf::Parser::is_regexp_valid at line 1388, avg 69µs/call
# 508 times (3.00ms+0s) by Mail::SpamAssassin::Conf::Parser::handle_conditional at line 511, avg 6µs/call
# 465 times (2.27ms+0s) by Mail::SpamAssassin::Conf::Parser::is_meta_valid at line 1294, avg 5µs/call
# 50 times (780µs+0s) by Mail::SpamAssassin::Conf::Parser::is_regexp_valid at line 1354, avg 16µs/call | |||||
sub Mail::SpamAssassin::Conf::Parser::CORE:sort; # opcode | |||||
# spent 265ms within Mail::SpamAssassin::Conf::Parser::CORE:subst which was called 92819 times, avg 3µs/call:
# 16436 times (64.6ms+0s) by Mail::SpamAssassin::Conf::Parser::parse at line 279, avg 4µs/call
# 16436 times (54.7ms+0s) by Mail::SpamAssassin::Conf::Parser::parse at line 282, avg 3µs/call
# 16436 times (39.5ms+0s) by Mail::SpamAssassin::Conf::Parser::parse at line 281, avg 2µs/call
# 16436 times (32.7ms+0s) by Mail::SpamAssassin::Conf::Parser::parse at line 280, avg 2µs/call
# 9050 times (22.0ms+0s) by Mail::SpamAssassin::Conf::Parser::parse at line 286, avg 2µs/call
# 7576 times (17.2ms+0s) by Mail::SpamAssassin::Conf::Parser::parse at line 291, avg 2µs/call
# 6034 times (19.4ms+0s) by Mail::SpamAssassin::Conf::Parser::is_regexp_valid at line 1344, avg 3µs/call
# 1686 times (3.24ms+0s) by Mail::SpamAssassin::Conf::Parser::find_dup_rules at line 1047, avg 2µs/call
# 548 times (1.51ms+0s) by Mail::SpamAssassin::Conf::Parser::add_test at line 1220, avg 3µs/call
# 483 times (2.67ms+0s) by Mail::SpamAssassin::Conf::Parser::pack_eval_method at line 1098, avg 6µs/call
# 483 times (1.01ms+0s) by Mail::SpamAssassin::Conf::Parser::pack_eval_method at line 1117, avg 2µs/call
# 379 times (3.08ms+0s) by Mail::SpamAssassin::Conf::Parser::pack_eval_method at line 1096, avg 8µs/call
# 379 times (898µs+0s) by Mail::SpamAssassin::Conf::Parser::pack_eval_method at line 1113, avg 2µs/call
# 97 times (736µs+0s) by Mail::SpamAssassin::Conf::Parser::add_to_addrlist_rcvd at line 1445, avg 8µs/call
# 97 times (418µs+0s) by Mail::SpamAssassin::Conf::Parser::add_to_addrlist_rcvd at line 1443, avg 4µs/call
# 97 times (235µs+0s) by Mail::SpamAssassin::Conf::Parser::add_to_addrlist_rcvd at line 1442, avg 2µs/call
# 50 times (413µs+0s) by Mail::SpamAssassin::Conf::Parser::is_regexp_valid at line 1354, avg 8µs/call
# 34 times (239µs+0s) by Mail::SpamAssassin::Conf::Parser::add_to_addrlist at line 1426, avg 7µs/call
# 34 times (150µs+0s) by Mail::SpamAssassin::Conf::Parser::add_to_addrlist at line 1424, avg 4µs/call
# 34 times (84µs+0s) by Mail::SpamAssassin::Conf::Parser::add_to_addrlist at line 1423, avg 2µs/call
# 14 times (113µs+0s) by Mail::SpamAssassin::Conf::Parser::is_regexp_valid at line 1345, avg 8µs/call | |||||
# spent 1.67ms within Mail::SpamAssassin::Conf::Parser::CORE:substcont which was called 479 times, avg 3µs/call:
# 361 times (1.25ms+0s) by Mail::SpamAssassin::Conf::Parser::add_to_addrlist_rcvd at line 1443, avg 3µs/call
# 118 times (424µs+0s) by Mail::SpamAssassin::Conf::Parser::add_to_addrlist at line 1424, avg 4µs/call |