1#!/usr/bin/perl 2 3# Copyright (C) 2006, 2007, 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# "check-for-exit-time-destructors" script for WebKit Open Source Project 30 31# Intended to be invoked from an Xcode build step to check if there are 32# any exit-time destructors in a target. 33 34use warnings; 35use strict; 36 37use File::Basename; 38 39sub touch($); 40sub printFunctions($$); 41 42my $arch = $ENV{'CURRENT_ARCH'}; 43my $configuration = $ENV{'CONFIGURATION'}; 44my $target = $ENV{'TARGET_NAME'}; 45my $variant = $ENV{'CURRENT_VARIANT'}; 46my $coverageBuild = $ENV{'WEBKIT_COVERAGE_BUILD'}; 47my $debugRoot = $ENV{'WEBKIT_DEBUG_ROOT'}; 48 49$arch = $ENV{'NATIVE_ARCH'} if !$arch; # for Xcode 2.1, which does not have CURRENT_ARCH 50$variant = "normal" if !$variant; # for Xcode 2.1, which does not have CURRENT_VARIANT 51 52my $executablePath = "$ENV{'TARGET_BUILD_DIR'}/$ENV{'EXECUTABLE_PATH'}"; 53 54my $buildTimestampPath = $ENV{'TARGET_TEMP_DIR'} . "/" . basename($0) . ".timestamp"; 55my $buildTimestampAge = -M $buildTimestampPath; 56my $scriptAge = -M $0; 57 58my $list = $ENV{"LINK_FILE_LIST_${variant}_${arch}"}; 59 60if (!open LIST, $list) { 61 print "ERROR: Could not open $list\n"; 62 exit 1; 63} 64 65my @files = <LIST>; 66chomp @files; 67close LIST; 68 69my $sawError = 0; 70 71for my $file (sort @files) { 72 if (defined $buildTimestampAge && $buildTimestampAge < $scriptAge) { 73 my $fileAge = -M $file; 74 next if defined $fileAge && $fileAge > $buildTimestampAge; 75 } 76 if (!open NM, "(nm '$file' | sed 's/^/STDOUT:/') 2>&1 |") { 77 print "ERROR: Could not open $file\n"; 78 $sawError = 1; 79 next; 80 } 81 my $sawAtExit = 0; 82 my $shortName = $file; 83 $shortName =~ s/.*\///; 84 85 while (<NM>) { 86 if (/^STDOUT:/) { 87 # With GC logging enabled Heap.o may contain finalizers, so we ignore them. 88 $sawAtExit = 1 if (/___cxa_atexit/ && ($shortName ne "Heap.o")); 89 } else { 90 print STDERR if $_ ne "nm: no name list\n"; 91 } 92 } 93 close NM; 94 next unless $sawAtExit; 95 96 $sawError = 1 if printFunctions($shortName, $file); 97} 98 99if ($sawError and !$coverageBuild) { 100 print "ERROR: Use DEFINE_STATIC_LOCAL from <wtf/StdLibExtras.h>\n"; 101 unlink $executablePath; 102 exit 1; 103} 104 105touch($buildTimestampPath); 106exit 0; 107 108sub touch($) 109{ 110 my ($path) = @_; 111 open(TOUCH, ">", $path) or die "$!"; 112 close(TOUCH); 113} 114 115sub demangle($) 116{ 117 my ($symbol) = @_; 118 if (!open FILT, "c++filt $symbol |") { 119 print "ERROR: Could not open c++filt\n"; 120 return; 121 } 122 my $result = <FILT>; 123 close FILT; 124 chomp $result; 125 return $result; 126} 127 128sub printFunctions($$) 129{ 130 my ($shortName, $path) = @_; 131 if (!open OTOOL, "otool -tV '$path' |") { 132 print "WARNING: Could not open $path\n"; 133 return 0; 134 } 135 my %functions; 136 my $currentSymbol = ""; 137 while (<OTOOL>) { 138 $currentSymbol = $1 if /^(\w+):$/; 139 next unless $currentSymbol; 140 $functions{demangle($currentSymbol)} = 1 if /___cxa_atexit/; 141 } 142 close OTOOL; 143 my $result = 0; 144 for my $function (sort keys %functions) { 145 if (!$result) { 146 print "ERROR: $shortName has exit time destructors in it! ($path)\n"; 147 $result = 1; 148 } 149 print "ERROR: In function $function\n"; 150 } 151 return $result; 152} 153