bug 518641 - fix the "unify" script to properly handle Java .class files. r=bsmedberg

Java .class files and Mach-O fat binaries use the same 4-byte magic
number at the start of the file. 'unify' uses the magic number to detect
Mach-O binaries, so it chokes on Java .class files. This change makes us
use the same heuristic as file(1), which is to check the second 4 bytes
in the file. Java class files put a version number there, and Mach-O
fat binaries put the number of contained architectures there. Conveniently,
Mach defines only 18 architectures, and Java's lowest shipping version
number is 43, so there's no overlap in valid values.

--HG--
extra : rebase_source : 84f5382bca6fa4bde721686f029514a41dfaf6b4
This commit is contained in:
Ted Mielczarek 2009-09-29 08:31:50 -04:00
Родитель b6437ef98e
Коммит 217e4c2081
5 изменённых файлов: 86 добавлений и 5 удалений

Просмотреть файл

@ -101,10 +101,47 @@ libs:: bloatcycle.html
ifeq ($(OS_ARCH),Darwin)
libs:: $(topsrcdir)/tools/rb/fix-macosx-stack.pl
$(INSTALL) $< $(DIST)/bin
# Basic unit tests for some stuff in the unify script
check::
# build ppc/i386 binaries, and unify them
rm -f unify-test-ppc unify-test-i386 unify-test-universal
$(HOST_CC) -arch ppc $(srcdir)/unify-test.c -o unify-test-ppc
$(HOST_CC) -arch i386 $(srcdir)/unify-test.c -o unify-test-i386
@if ! $(srcdir)/macosx/universal/unify ./unify-test-ppc ./unify-test-i386 \
./unify-test-universal; then \
echo "TEST-UNEXPECTED-FAIL | build/ | unify failed to produce a universal binary!"; \
false; \
fi
@if ! test -f ./unify-test-universal; then \
echo "TEST-UNEXPECTED-FAIL | build/ | unify failed to produce a universal binary!"; \
false; \
fi
@if ! file -b ./unify-test-universal | head -n1 | grep -q "^Mach-O universal binary"; then \
echo "TEST-UNEXPECTED-FAIL | build/ | unify failed to produce a universal binary!"; \
false; \
fi
# try unifying two identical Java class files
rm -f unifytesta.class unifytestb.class unifytestc.class
cp $(srcdir)/unifytest.class ./unifytesta.class
cp $(srcdir)/unifytest.class ./unifytestb.class
@if ! $(srcdir)/macosx/universal/unify ./unifytesta.class ./unifytestb.class \
./unifytestc.class; then \
echo "TEST-UNEXPECTED-FAIL | build/ | unify failed to unify a Java class file!"; \
false; \
fi
@if ! test -f ./unifytestc.class; then \
echo "TEST-UNEXPECTED-FAIL | build/ | unify failed to unify a Java class file!"; \
false; \
fi
@if ! diff -q ./unifytesta.class ./unifytestc.class; then \
echo "TEST-UNEXPECTED-FAIL | build/ | unify failed to unify a Java class file!"; \
false; \
fi
endif
ifeq ($(OS_ARCH),Linux)
libs:: $(topsrcdir)/tools/rb/fix-linux-stack.pl
$(INSTALL) $< $(DIST)/bin
endif
endif
endif # ENABLE_TESTS

Просмотреть файл

@ -214,6 +214,7 @@ sub readZipCRCs($);
sub lstatMode($);
sub lstatType($);
sub magic($);
sub magic2($);
sub path($);
sub stat($);
sub statSize($);
@ -1053,6 +1054,7 @@ sub readZipCRCs($) {
'lstatErrno' => 0,
'lstatInit' => 0,
'magic' => undef,
'magic2' => undef,
'magicErrno' => 0,
'magicErrMsg' => undef,
'magicInit' => 0,
@ -1069,7 +1071,7 @@ sub readZipCRCs($) {
# Returns true if the file is a fat Mach-O file, false if it's not, and
# undef if an error occurs. See /usr/include/mach-o/fat.h.
sub isFat($) {
my ($magic, $this);
my ($magic, $magic2, $this);
($this) = @_;
# magic() caches, there's no separate cache because isFat() doesn't hit
@ -1078,8 +1080,16 @@ sub readZipCRCs($) {
if (!defined($magic = $this->magic())) {
return undef;
}
$magic2 = $this->magic2();
if ($magic == 0xcafebabe) {
# We have to sanity check the second four bytes, because Java class
# files use the same magic number as Mach-O fat binaries.
# This logic is adapted from file(1), which says that Mach-O uses
# these bytes to count the number of architectures within, while
# Java uses it for a version number. Conveniently, there are only
# 18 labelled Mach-O architectures, and Java's first released
# class format used the version 43.0.
if ($magic == 0xcafebabe && $magic2 < 20) {
return 1;
}
@ -1105,7 +1115,7 @@ sub readZipCRCs($) {
# Accept Mach-O fat files or Mach-O thin files of either endianness.
if ($magic == 0xfeedface ||
$magic == 0xcefaedfe ||
$magic == 0xcafebabe) {
$this->isFat()) {
return 1;
}
@ -1292,7 +1302,7 @@ sub readZipCRCs($) {
}
$! = 0;
my ($bytes, $magic);
my ($bytes, $magic, $bytes2, $magic2);
if (!defined($bytes = sysread($fh, $magic, 4))) {
$$this{'magicErrno'} = $!;
$$this{'magicErrMsg'} = 'read "'.$$this{'path'}.'": '.$!;
@ -1301,6 +1311,9 @@ sub readZipCRCs($) {
close($fh);
return undef;
}
else {
$bytes2 = sysread($fh, $magic2, 4);
}
close($fh);
@ -1308,13 +1321,35 @@ sub readZipCRCs($) {
# The file is too short, didn't read a magic number. This isn't really
# an error. Return an unlikely value.
$$this{'magic'} = -1;
$$this{'magic2'} = -1;
return -1;
}
if ($bytes2 != 4) {
# File is too short to read a second 4 bytes.
$magic2 = -1;
}
$$this{'magic'} = unpack('N', $magic);
$$this{'magic2'} = unpack('N', $magic2);
return $$this{'magic'};
}
# $FileAttrCache->magic2()
#
# Returns the second four bytes of the file as a 32-bit little endian number.
# See magic(), above for more info.
sub magic2($) {
my ($this);
($this) = @_;
# we do the actual work (and cache it) in magic().
if (!$$this{'magicInit'}) {
my $magic = $$this->magic();
}
return $$this{'magic2'};
}
# $FileAttrCache->path()
#
# Returns the file's pathname.

4
build/unify-test.c Normal file
Просмотреть файл

@ -0,0 +1,4 @@
int main(int argc, char** argv)
{
return 0;
}

Двоичные данные
build/unifytest.class Normal file

Двоичный файл не отображается.

5
build/unifytest.java Normal file
Просмотреть файл

@ -0,0 +1,5 @@
class unifytest {
public static void main(String[] args) {
return;
}
}