Skip to content

Commit 0c703a9

Browse files
committed
Bug 1178094 - Update crash signatures to match new Socorro signature generation
1 parent c0de3b6 commit 0c703a9

File tree

1 file changed

+199
-0
lines changed

1 file changed

+199
-0
lines changed

scripts/update-crash-signatures.pl

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
#!/usr/bin/perl
2+
3+
# This Source Code Form is subject to the terms of the Mozilla Public
4+
# License, v. 2.0. If a copy of the MPL was not distributed with this
5+
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
6+
#
7+
# This Source Code Form is "Incompatible With Secondary Licenses", as
8+
# defined by the Mozilla Public License, v. 2.0.
9+
10+
use strict;
11+
use warnings;
12+
$| = 1;
13+
14+
use FindBin qw($RealBin);
15+
use lib "$RealBin/..", "$RealBin/../lib";
16+
17+
use constant BATCH_SIZE => 100;
18+
19+
use Bugzilla;
20+
use Bugzilla::Bug;
21+
use Bugzilla::Constants;
22+
use Bugzilla::Util qw( trim );
23+
use List::MoreUtils qw( any );
24+
use Text::Balanced qw( extract_bracketed extract_multiple );
25+
26+
Bugzilla->usage_mode(USAGE_MODE_CMDLINE);
27+
28+
my $user = Bugzilla::User->check({ name => 'automation@bmo.tld' });
29+
$user->{groups} = [ Bugzilla::Group->get_all ];
30+
$user->{bless_groups} = [ Bugzilla::Group->get_all ];
31+
Bugzilla->set_user($user);
32+
33+
my $dbh = Bugzilla->dbh;
34+
35+
# find the bugs
36+
37+
my $bugs = $dbh->selectall_arrayref(
38+
"SELECT bug_id,cf_crash_signature FROM bugs WHERE resolution = '' AND cf_crash_signature != ''",
39+
{ Slice => {} }
40+
);
41+
my $count = scalar @$bugs;
42+
43+
# update
44+
45+
die "No bugs found\n" unless $count;
46+
print "Found $count open bug(s) with crash signatures\nPress <Ctrl-C> to stop or <Enter> to continue..\n";
47+
getc();
48+
49+
my $updated = 0;
50+
foreach my $rh_bug (@$bugs) {
51+
my $bug_id = $rh_bug->{bug_id};
52+
my $signature = $rh_bug->{cf_crash_signature};
53+
54+
# check for updated signature
55+
my $collapsed = collapse($signature);
56+
next if is_same($signature, $collapsed);
57+
58+
# ignore signatures malformed in a way that would result in updating on each pass
59+
next if $collapsed ne collapse($collapsed);
60+
61+
# update the bug, preventing bugmail
62+
print "$bug_id\n";
63+
$dbh->bz_start_transaction;
64+
my $bug = Bugzilla::Bug->check($bug_id);
65+
$bug->set_all({ cf_crash_signature => $collapsed });
66+
$bug->update();
67+
$dbh->do("UPDATE bugs SET lastdiffed = delta_ts WHERE bug_id = ?", undef, $bug_id);
68+
$dbh->bz_commit_transaction;
69+
70+
# object caching causes us to consume a lot of memory
71+
# process in batches
72+
last if ++$updated == BATCH_SIZE;
73+
}
74+
print "Updated $updated bugs(s)\n";
75+
76+
sub is_same {
77+
my ($old, $new) = @_;
78+
$old =~ s/[\015\012]+/ /g;
79+
$new =~ s/[\015\012]+/ /g;
80+
return trim($old) eq trim($new);
81+
}
82+
83+
sub collapse {
84+
my ($crash_signature) = @_;
85+
86+
# ignore completely invalid signatures
87+
return $crash_signature unless $crash_signature =~ /\[/ && $crash_signature =~ /\]/;
88+
89+
# split
90+
my @signatures =
91+
grep { /\S/ }
92+
extract_multiple($crash_signature, [ sub { extract_bracketed($_[0], '[]') } ]);
93+
my @unbracketed = map { unbracketed($_) } @signatures;
94+
95+
foreach my $signature (@signatures) {
96+
# ignore invalid signatures
97+
next unless $signature =~ /^\s*\[/;
98+
next if unbracketed($signature) =~ /\.\.\.$/;
99+
100+
# collpase
101+
my $collapsed = collapse_crash_sig({
102+
signature => $signature,
103+
open => '<',
104+
replacement_open => '<',
105+
close => '>',
106+
replacement_close => 'T>',
107+
exceptions => [],
108+
});
109+
$collapsed = collapse_crash_sig({
110+
signature => $collapsed,
111+
open => '(',
112+
replacement_open => '',
113+
close => ')',
114+
replacement_close => '',
115+
exceptions => ['anonymous namespace', 'operator'],
116+
});
117+
$collapsed =~ s/\s+/ /g;
118+
119+
# ignore sigs that collapse down to nothing
120+
next if $collapsed eq '[@ ]';
121+
122+
# don't create duplicates
123+
my $unbracketed = unbracketed($collapsed);
124+
next if any { $unbracketed eq $_ } @unbracketed;
125+
126+
push @signatures, $collapsed;
127+
push @unbracketed, $unbracketed;
128+
}
129+
130+
return join("\015\012", map { trim($_) } @signatures);
131+
}
132+
133+
sub unbracketed {
134+
my ($signature) = @_;
135+
$signature =~ s/(^\s*\[\s*|\s*\]\s*$)//g;
136+
return $signature;
137+
}
138+
139+
# collapsing code lifted from socorro:
140+
# https://github.com/mozilla/socorro/blob/master/socorro/processor/signature_utilities.py#L110
141+
142+
my ($target_counter, $exception_mode, @collapsed);
143+
144+
sub append_if_not_in_collapse_mode {
145+
my ($character) = @_;
146+
if (!$target_counter) {
147+
push @collapsed, $character;
148+
}
149+
}
150+
151+
sub is_exception {
152+
my ($exceptions, $remaining_original_line, $line_up_to_current_position) = @_;
153+
foreach my $exception (@$exceptions) {
154+
if (substr($remaining_original_line, 0, length($exception)) eq $exception) {
155+
return 1;
156+
}
157+
if (substr($line_up_to_current_position, -length($exception)) eq $exception) {
158+
return 1;
159+
}
160+
}
161+
return 0;
162+
}
163+
164+
sub collapse_crash_sig {
165+
my ($params) = @_;
166+
167+
$target_counter = 0;
168+
@collapsed = ();
169+
$exception_mode = 0;
170+
my $signature = $params->{signature};
171+
172+
for (my $i = 0; $i < length($signature); $i++) {
173+
my $character = substr($signature, $i, 1);
174+
if ($character eq $params->{open}) {
175+
if (is_exception($params->{exceptions}, substr($signature, $i + 1), substr($signature, 0, $i))) {
176+
$exception_mode = 1;
177+
append_if_not_in_collapse_mode($character);
178+
next;
179+
}
180+
append_if_not_in_collapse_mode($params->{replacement_open});
181+
$target_counter++;
182+
}
183+
elsif ($character eq $params->{close}) {
184+
if ($exception_mode) {
185+
append_if_not_in_collapse_mode($character);
186+
$exception_mode = 0;
187+
}
188+
else {
189+
$target_counter--;
190+
append_if_not_in_collapse_mode($params->{replacement_close});
191+
}
192+
}
193+
else {
194+
append_if_not_in_collapse_mode($character);
195+
}
196+
}
197+
198+
return join '', @collapsed;
199+
}

0 commit comments

Comments
 (0)