1 #!/usr/bin/perl -w 2 3 # Copyright (C) 2008 Apple Inc. All rights reserved. 4 # 5 # Redistribution and use in source and binary forms, with or without 6 # modification, are permitted provided that the following conditions 7 # are met: 8 # 9 # 1. Redistributions of source code must retain the above copyright 10 # notice, this list of conditions and the following disclaimer. 11 # 2. Redistributions in binary form must reproduce the above copyright 12 # notice, this list of conditions and the following disclaimer in the 13 # documentation and/or other materials provided with the distribution. 14 # 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 15 # its contributors may be used to endorse or promote products derived 16 # from this software without specific prior written permission. 17 # 18 # THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 # DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 # THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 # 30 # This script attempts to find instances of a problem where the signatures 31 # of virtual methods fail to match because one is defined 'const', and another 32 # is not. For example: 33 # virtual void Base::doStuff() const; 34 # virtual void Derived::doStuff(); 35 # 36 # The lack of 'const' on the derived class gives it a different signature, and 37 # it will therefore not be called when doStuff() is called on a derived object 38 # via a base class pointer. 39 # 40 # Limitations of this script: 41 # * It only works on things in the WebCore namespace 42 # * Not all templatized methods may be found correctly 43 # * It doesn't know anything about inheritance, or if methods are actually virtual 44 # * It has lots of false positives (should add a whitelist for known-good signatures, 45 # and specific methods) 46 # * It's rather slow 47 # 48 # Added by Simon Fraser <simon.fraser (at] apple.com> 49 # 50 # Run the script like this: 51 # WebKitTools/Scripts/detect-mismatched-virtual-const WebKitBuild/Debug/WebCore.framework/WebCore 52 # 53 # Output consists of a series of warnings like this: 54 # 55 # Both const and non-const versions of bgColor(): 56 # HTMLDocument::bgColor() 57 # HTMLBodyElement::bgColor() const 58 # HTMLTableElement::bgColor() const 59 # HTMLTableRowElement::bgColor() const 60 # HTMLTableCellElement::bgColor() const 61 # 62 63 use strict; 64 no warnings qw /syntax/; 65 66 67 my $file = $ARGV[0]; 68 69 print "Looking for unmatched const methods in $file\n"; 70 71 if (!open NM, "(nm '$file' | c++filt | sed 's/^/STDOUT:/') 2>&1 |") { 72 die "Could not open $file\n"; 73 } 74 75 my $nestedParens; 76 $nestedParens = qr / 77 [(] 78 [^()]* 79 (?: 80 (??{ $nestedParens }) 81 [^()]* 82 )* 83 [)]/x; 84 85 my $nestedAngleBrackets; 86 $nestedAngleBrackets = qr / 87 [<] 88 [^<>]* 89 (?: 90 (??{ $nestedAngleBrackets }) 91 [^<>]* 92 )* 93 [>]/x; 94 95 my $bal; 96 $bal = qr /([^:]+ 97 (??{ $nestedAngleBrackets })? 98 (??{ $nestedParens })) 99 ([^()]*)$/x; 100 101 my %signature_map = (); 102 103 while (<NM>) { 104 my $line = $_; 105 chomp($line); 106 if ($line =~ m/ [tT] WebCore::(.+)$/) { 107 my $method = $1; 108 109 if ($method =~ /$bal/) { 110 my $signature = $1; 111 my $const = $2 eq " const"; 112 113 my $class = substr($method, 0, length($method) - length($signature) - ($const ? 6 : 0)); 114 115 # print "line: $line\nclass: $class\nmethod: $method\nsignature: $signature\nconst: $const\n\n"; 116 117 my %method_info = ( 118 'class' => $class, 119 'const' => $const, 120 'method' => $method, 121 ); 122 123 push @{$signature_map{$signature}}, \%method_info; 124 } else { 125 print "unmatched line $method\n\n" 126 } 127 } 128 } 129 close NM; 130 131 my $sig; 132 for $sig (keys %signature_map) { 133 #print "\n$sig\n"; 134 135 my @entries = @{$signature_map{$sig}}; 136 # print "$#entries\n"; 137 138 my $num_const = 0; 139 my $num_not_const = 0; 140 my $i; 141 for $i (0 .. $#entries) { 142 my $entry = @entries[$i]; 143 144 my $class = $entry->{'class'}; 145 my $const = $entry->{'const'}; 146 147 if ($const) { 148 $num_const++; 149 } else { 150 $num_not_const++; 151 } 152 } 153 154 if ($#entries > 1 && $num_const > 0 && $num_not_const > 0) { 155 print "Both const and non-const versions of $sig:\n"; 156 157 for $i (0 .. $#entries) { 158 my $entry = @entries[$i]; 159 my $method = $entry->{'method'}; 160 print "\t$method\n"; 161 } 162 163 } 164 } 165 166 167 168