Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(502)

Side by Side Diff: base/metrics/field_trial.cc

Issue 2511413002: Add debug info for field trial allocation crash (Closed)
Patch Set: iterate through allocator to check for existing allocator Created 4 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/metrics/field_trial.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 163 matching lines...) Expand 10 before | Expand all | Expand 10 after
174 174
175 void AddForceFieldTrialsFlag(CommandLine* cmd_line) { 175 void AddForceFieldTrialsFlag(CommandLine* cmd_line) {
176 std::string field_trial_states; 176 std::string field_trial_states;
177 FieldTrialList::AllStatesToString(&field_trial_states); 177 FieldTrialList::AllStatesToString(&field_trial_states);
178 if (!field_trial_states.empty()) { 178 if (!field_trial_states.empty()) {
179 cmd_line->AppendSwitchASCII(switches::kForceFieldTrials, 179 cmd_line->AppendSwitchASCII(switches::kForceFieldTrials,
180 field_trial_states); 180 field_trial_states);
181 } 181 }
182 } 182 }
183 183
184 // In order to debug the crash where two field trials with the same name but
185 // different groups get added to the allocator, let's try to get the stack
186 // frame where the second duplicate gets added here as well as the trial/group
187 // names by going through the allocator and checking if a trial with the same
188 // name already exists.
189 void CheckAllocatorForTrial(FieldTrialList::FieldTrialAllocator* allocator,
190 std::string trial_name,
Alexei Svitkine (slow) 2016/11/21 20:11:33 Nit: const& Same for the next param.
lawrencewu 2016/11/21 20:41:23 Done.
191 std::string group_name) {
192 FieldTrialList::FieldTrialAllocator::Iterator iter(allocator);
193 FieldTrial::FieldTrialRef ref;
194 while ((ref = iter.GetNextOfType(kFieldTrialType)) !=
195 FieldTrialList::FieldTrialAllocator::kReferenceNull) {
196 const FieldTrialEntry* entry =
197 allocator->GetAsObject<const FieldTrialEntry>(ref, kFieldTrialType);
198
199 StringPiece trial_name_to_check;
200 StringPiece group_name_to_check;
201 if (!entry->GetTrialAndGroupName(&trial_name_to_check,
202 &group_name_to_check))
Alexei Svitkine (slow) 2016/11/21 20:11:33 Nit: {}'s
lawrencewu 2016/11/21 20:41:23 Done.
203 CHECK(false);
204
205 std::string existing_trial_name = trial_name_to_check.as_string();
206 std::string existing_group_name = group_name_to_check.as_string();
207 if (existing_trial_name == trial_name) {
208 constexpr size_t buf_size = 100;
209
210 char trial_name_c_str[buf_size];
211 char group_name_c_str[buf_size];
212 char existing_group_name_c_str[buf_size];
213
214 strlcpy(trial_name_c_str, trial_name.c_str(), buf_size);
215 strlcpy(group_name_c_str, group_name.c_str(), buf_size);
216 strlcpy(existing_group_name_c_str, existing_group_name.c_str(), buf_size);
217
218 debug::Alias(trial_name_c_str);
219 debug::Alias(existing_group_name_c_str);
220 debug::Alias(group_name_c_str);
221 CHECK_EQ(existing_group_name, group_name);
222 }
223 }
224 }
225
184 #if defined(OS_WIN) 226 #if defined(OS_WIN)
185 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) { 227 HANDLE CreateReadOnlyHandle(FieldTrialList::FieldTrialAllocator* allocator) {
186 HANDLE src = allocator->shared_memory()->handle().GetHandle(); 228 HANDLE src = allocator->shared_memory()->handle().GetHandle();
187 ProcessHandle process = GetCurrentProcess(); 229 ProcessHandle process = GetCurrentProcess();
188 DWORD access = SECTION_MAP_READ | SECTION_QUERY; 230 DWORD access = SECTION_MAP_READ | SECTION_QUERY;
189 HANDLE dst; 231 HANDLE dst;
190 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0)) 232 if (!::DuplicateHandle(process, src, process, &dst, access, true, 0))
191 return nullptr; 233 return nullptr;
192 return dst; 234 return dst;
193 } 235 }
(...skipping 656 matching lines...) Expand 10 before | Expand all | Expand 10 after
850 return false; 892 return false;
851 893
852 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take 894 // TODO(lawrencewu): Convert the API for CreateFieldTrial to take
853 // StringPieces. 895 // StringPieces.
854 FieldTrial* trial = 896 FieldTrial* trial =
855 CreateFieldTrial(trial_name.as_string(), group_name.as_string()); 897 CreateFieldTrial(trial_name.as_string(), group_name.as_string());
856 898
857 // If we failed to create the field trial, crash with debug info. 899 // If we failed to create the field trial, crash with debug info.
858 // TODO(665129): Remove this when the crash is resolved. 900 // TODO(665129): Remove this when the crash is resolved.
859 if (!trial) { 901 if (!trial) {
902 constexpr size_t buf_size = 100;
903 char trial_name_c_str[buf_size] = {0};
904 char group_name_c_str[buf_size] = {0};
905 char existing_group_name_c_str[buf_size] = {0};
906
907 // Copy the names over to the stack.
860 std::string trial_name_string = trial_name.as_string(); 908 std::string trial_name_string = trial_name.as_string();
909 strlcpy(trial_name_c_str, trial_name_string.c_str(), buf_size);
861 std::string group_name_string = group_name.as_string(); 910 std::string group_name_string = group_name.as_string();
911 strlcpy(group_name_c_str, group_name_string.c_str(), buf_size);
912
913 // Alias the trial and group name.
914 debug::Alias(trial_name_c_str);
915 debug::Alias(group_name_c_str);
916
917 // Copy and alias the existing field trial name, if there is one.
862 FieldTrial* existing_field_trial = 918 FieldTrial* existing_field_trial =
863 FieldTrialList::Find(trial_name_string); 919 FieldTrialList::Find(trial_name_string);
864 if (existing_field_trial) 920 if (existing_field_trial) {
865 debug::Alias(existing_field_trial->group_name_internal().c_str()); 921 std::string existing_group_name_string =
866 debug::Alias(trial_name_string.c_str()); 922 existing_field_trial->group_name_internal();
867 debug::Alias(group_name_string.c_str()); 923 strlcpy(existing_group_name_c_str, group_name_string.c_str(), buf_size);
924 debug::Alias(existing_group_name_c_str);
925 }
868 CHECK(!trial_name_string.empty()); 926 CHECK(!trial_name_string.empty());
869 CHECK(!group_name_string.empty()); 927 CHECK(!group_name_string.empty());
870 CHECK_EQ(existing_field_trial->group_name_internal(), 928 CHECK_EQ(existing_field_trial->group_name_internal(),
871 group_name.as_string()); 929 group_name.as_string());
872 return false; 930 return false;
873 } 931 }
874 932
875 trial->ref_ = ref; 933 trial->ref_ = ref;
876 if (entry->activated) { 934 if (entry->activated) {
877 // Call |group()| to mark the trial as "used" and notify observers, if 935 // Call |group()| to mark the trial as "used" and notify observers, if
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
912 global_->readonly_allocator_handle_ = 970 global_->readonly_allocator_handle_ =
913 CreateReadOnlyHandle(global_->field_trial_allocator_.get()); 971 CreateReadOnlyHandle(global_->field_trial_allocator_.get());
914 #endif 972 #endif
915 } 973 }
916 #endif 974 #endif
917 975
918 // static 976 // static
919 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) { 977 void FieldTrialList::AddToAllocatorWhileLocked(FieldTrial* field_trial) {
920 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get(); 978 FieldTrialAllocator* allocator = global_->field_trial_allocator_.get();
921 979
980 // TODO(665129): Remove this code once the bug has been fixed.
981 CheckAllocatorForTrial(allocator, field_trial->trial_name(),
982 field_trial->group_name_internal());
983
922 // Don't do anything if the allocator hasn't been instantiated yet. 984 // Don't do anything if the allocator hasn't been instantiated yet.
923 if (allocator == nullptr) 985 if (allocator == nullptr)
924 return; 986 return;
925 987
926 // Or if the allocator is read only, which means we are in a child process and 988 // Or if the allocator is read only, which means we are in a child process and
927 // shouldn't be writing to it. 989 // shouldn't be writing to it.
928 if (allocator->IsReadonly()) 990 if (allocator->IsReadonly())
929 return; 991 return;
930 992
931 FieldTrial::State trial_state; 993 FieldTrial::State trial_state;
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
1010 return; 1072 return;
1011 } 1073 }
1012 AutoLock auto_lock(global_->lock_); 1074 AutoLock auto_lock(global_->lock_);
1013 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name(); 1075 CHECK(!global_->PreLockedFind(trial->trial_name())) << trial->trial_name();
1014 trial->AddRef(); 1076 trial->AddRef();
1015 trial->SetTrialRegistered(); 1077 trial->SetTrialRegistered();
1016 global_->registered_[trial->trial_name()] = trial; 1078 global_->registered_[trial->trial_name()] = trial;
1017 } 1079 }
1018 1080
1019 } // namespace base 1081 } // namespace base
OLDNEW
« no previous file with comments | « base/metrics/field_trial.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698