OLD | NEW |
---|---|
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/metrics/field_trial.h" | 5 #include "base/metrics/field_trial.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/base_switches.h" | 10 #include "base/base_switches.h" |
(...skipping 166 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
177 | 177 |
178 void AddForceFieldTrialsFlag(CommandLine* cmd_line) { | 178 void AddForceFieldTrialsFlag(CommandLine* cmd_line) { |
179 std::string field_trial_states; | 179 std::string field_trial_states; |
180 FieldTrialList::AllStatesToString(&field_trial_states); | 180 FieldTrialList::AllStatesToString(&field_trial_states); |
181 if (!field_trial_states.empty()) { | 181 if (!field_trial_states.empty()) { |
182 cmd_line->AppendSwitchASCII(switches::kForceFieldTrials, | 182 cmd_line->AppendSwitchASCII(switches::kForceFieldTrials, |
183 field_trial_states); | 183 field_trial_states); |
184 } | 184 } |
185 } | 185 } |
186 | 186 |
187 // In order to debug the crash where two field trials with the same name but | |
188 // different groups get added to the allocator, let's try to get the stack | |
189 // frame where the second duplicate gets added here as well as the trial/group | |
190 // names by going through the allocator and checking if a trial with the same | |
191 // name already exists. | |
192 void CheckAllocatorForTrial(FieldTrialList::FieldTrialAllocator* allocator, | |
193 const std::string& trial_name, | |
194 const std::string& group_name) { | |
195 FieldTrialList::FieldTrialAllocator::Iterator iter(allocator); | |
196 FieldTrial::FieldTrialRef ref; | |
197 while ((ref = iter.GetNextOfType(kFieldTrialType)) != | |
198 FieldTrialList::FieldTrialAllocator::kReferenceNull) { | |
199 const FieldTrialEntry* entry = | |
200 allocator->GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType); | |
201 | |
202 StringPiece trial_name_to_check; | |
203 StringPiece group_name_to_check; | |
204 if (!entry->GetTrialAndGroupName(&trial_name_to_check, | |
205 &group_name_to_check)) { | |
206 CHECK(false); | |
207 } | |
208 | |
209 if (trial_name_to_check.as_string() == trial_name) { | |
210 constexpr size_t buf_size = 100; | |
211 | |
212 char trial_name_c_str[buf_size]; | |
213 char group_name_c_str[buf_size]; | |
214 char existing_group_name_c_str[buf_size]; | |
215 | |
216 strlcpy(trial_name_c_str, trial_name.c_str(), buf_size); | |
217 strlcpy(group_name_c_str, group_name.c_str(), buf_size); | |
218 strlcpy(existing_group_name_c_str, | |
219 group_name_to_check.as_string().c_str(), buf_size); | |
brucedawson
2016/11/22 17:55:24
Unfortunately, calling as_string() is exactly as e
Alexei Svitkine (slow)
2016/11/22 18:49:30
+1
You should be able to strlcpy() from the Strin
| |
220 | |
221 debug::Alias(trial_name_c_str); | |
222 debug::Alias(group_name_c_str); | |
223 debug::Alias(existing_group_name_c_str); | |
224 CHECK_EQ(group_name_to_check.as_string(), group_name); | |
225 } | |
226 } | |
227 } | |
228 | |
187 #if defined(OS_WIN) | 229 #if defined(OS_WIN) |
188 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { | 230 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { |
189 HANDLE src = allocator->shared_memory()->handle().GetHandle(); | 231 HANDLE src = allocator->shared_memory()->handle().GetHandle(); |
190 ProcessHandle process = GetCurrentProcess(); | 232 ProcessHandle process = GetCurrentProcess(); |
191 DWORD access = SECTION_MAP_READ | SECTION_QUERY; | 233 DWORD access = SECTION_MAP_READ | SECTION_QUERY; |
192 HANDLE dst; | 234 HANDLE dst; |
193 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) | 235 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) |
194 return nullptr; | 236 return nullptr; |
195 return dst; | 237 return dst; |
196 } | 238 } |
(...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
853 return false; | 895 return false; |
854 | 896 |
855 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take | 897 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take |
856 // StringPieces. | 898 // StringPieces. |
857 FieldTrial* trial = | 899 FieldTrial* trial = |
858 CreateFieldTrial(trial_name.as_string(), group_name.as_string()); | 900 CreateFieldTrial(trial_name.as_string(), group_name.as_string()); |
859 | 901 |
860 // If we failed to create the field trial, crash with debug info. | 902 // If we failed to create the field trial, crash with debug info. |
861 // TODO(665129): Remove this when the crash is resolved. | 903 // TODO(665129): Remove this when the crash is resolved. |
862 if (!trial) { | 904 if (!trial) { |
905 constexpr size_t buf_size = 100; | |
906 char trial_name_c_str[buf_size] = {0}; | |
907 char group_name_c_str[buf_size] = {0}; | |
908 char existing_group_name_c_str[buf_size] = {0}; | |
909 | |
910 // Copy the names over to the stack. | |
863 std::string trial_name_string = trial_name.as_string(); | 911 std::string trial_name_string = trial_name.as_string(); |
912 strlcpy(trial_name_c_str, trial_name_string.c_str(), buf_size); | |
864 std::string group_name_string = group_name.as_string(); | 913 std::string group_name_string = group_name.as_string(); |
914 strlcpy(group_name_c_str, group_name_string.c_str(), buf_size); | |
915 | |
916 // Alias the trial and group name. | |
917 debug::Alias(trial_name_c_str); | |
918 debug::Alias(group_name_c_str); | |
919 | |
920 // Copy and alias the existing field trial name, if there is one. | |
865 FieldTrial* existing_field_trial = | 921 FieldTrial* existing_field_trial = |
866 FieldTrialList::Find(trial_name_string); | 922 FieldTrialList::Find(trial_name_string); |
867 if (existing_field_trial) | 923 if (existing_field_trial) { |
868 debug::Alias(existing_field_trial->group_name_internal().c_str()); | 924 std::string existing_group_name_string = |
869 debug::Alias(trial_name_string.c_str()); | 925 existing_field_trial->group_name_internal(); |
870 debug::Alias(group_name_string.c_str()); | 926 strlcpy(existing_group_name_c_str, group_name_string.c_str(), buf_size); |
927 debug::Alias(existing_group_name_c_str); | |
928 } | |
871 CHECK(!trial_name_string.empty()); | 929 CHECK(!trial_name_string.empty()); |
872 CHECK(!group_name_string.empty()); | 930 CHECK(!group_name_string.empty()); |
873 CHECK_EQ(existing_field_trial->group_name_internal(), | 931 CHECK_EQ(existing_field_trial->group_name_internal(), |
874 group_name.as_string()); | 932 group_name.as_string()); |
875 return false; | 933 return false; |
876 } | 934 } |
877 | 935 |
878 trial->ref_ = ref; | 936 trial->ref_ = ref; |
879 if (entry->activated) { | 937 if (entry->activated) { |
880 // Call |group()| to mark the trial as "used" and notify observers, if | 938 // Call |group()| to mark the trial as "used" and notify observers, if |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
924 | 982 |
925 // Don't do anything if the allocator hasn't been instantiated yet. | 983 // Don't do anything if the allocator hasn't been instantiated yet. |
926 if (allocator == nullptr) | 984 if (allocator == nullptr) |
927 return; | 985 return; |
928 | 986 |
929 // Or if the allocator is read only, which means we are in a child process and | 987 // Or if the allocator is read only, which means we are in a child process and |
930 // shouldn't be writing to it. | 988 // shouldn't be writing to it. |
931 if (allocator->IsReadonly()) | 989 if (allocator->IsReadonly()) |
932 return; | 990 return; |
933 | 991 |
992 // TODO(665129): Remove this code once the bug has been fixed. | |
993 CheckAllocatorForTrial(allocator, field_trial->trial_name(), | |
994 field_trial->group_name_internal()); | |
995 | |
934 FieldTrial::State trial_state; | 996 FieldTrial::State trial_state; |
935 if (!field_trial->GetStateWhileLocked(&trial_state)) | 997 if (!field_trial->GetStateWhileLocked(&trial_state)) |
936 return; | 998 return; |
937 | 999 |
938 // Or if we've already added it. We must check after GetState since it can | 1000 // Or if we've already added it. We must check after GetState since it can |
939 // also add to the allocator. | 1001 // also add to the allocator. |
940 if (field_trial->ref_) | 1002 if (field_trial->ref_) |
941 return; | 1003 return; |
942 | 1004 |
943 Pickle pickle; | 1005 Pickle pickle; |
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1013 return; | 1075 return; |
1014 } | 1076 } |
1015 AutoLock auto_lock(global_->lock_); | 1077 AutoLock auto_lock(global_->lock_); |
1016 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); | 1078 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); |
1017 trial->AddRef(); | 1079 trial->AddRef(); |
1018 trial->SetTrialRegistered(); | 1080 trial->SetTrialRegistered(); |
1019 global_->registered_[trial->trial_name()] = trial; | 1081 global_->registered_[trial->trial_name()] = trial; |
1020 } | 1082 } |
1021 | 1083 |
1022 } // namespace base | 1084 } // namespace base |
OLD | NEW |