diff options
Diffstat (limited to 'content')
-rw-r--r-- | content/browser/mac/closure_blocks_leopard_compat.S | 139 | ||||
-rw-r--r-- | content/browser/mac/closure_blocks_leopard_compat.h | 104 | ||||
-rw-r--r-- | content/browser/mac/closure_blocks_leopard_compat_unittest.cc | 98 | ||||
-rw-r--r-- | content/content.gyp | 62 | ||||
-rw-r--r-- | content/content_tests.gypi | 6 |
5 files changed, 409 insertions, 0 deletions
diff --git a/content/browser/mac/closure_blocks_leopard_compat.S b/content/browser/mac/closure_blocks_leopard_compat.S new file mode 100644 index 0000000..88a63da --- /dev/null +++ b/content/browser/mac/closure_blocks_leopard_compat.S @@ -0,0 +1,139 @@ +# Copyright (c) 2011 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +# Definitions of symbols that may be needed at runtime but aren't necessarily +# present in the SDK chosen for compilation. +# +# This file provides symbols for _NSConcreteGlobalBlock and +# _NSConcreteStackBlock, normally present in libSystem.dylib and provided by +# by libclosure-38/data.c in Mac OS X 10.6 and later. It also provides symbols +# for various block runtime functions provided by libclosure-38/runtime.c. +# When using the 10.5 SDK, the symbols are not present. This file's definition +# can be used with extreme care in an application that needs to use the 10.5 +# SDK in conjunction with blocks. +# +# This file cooperates with the build system to produce a dynamic library +# that, when linked against, causes dependents to look in libSystem for the +# symbols provided here. It also cooperates with a header that causes +# dependents to treat the symbols provided here as weak imports, critical for +# the resultant output to be loadable on 10.5. + +# To simplify things, this file assumes it's being built with the 10.5 SDK, +# a deployment target of 10.5, and is producing 32-bit x86 code. Other +# combinations are possible, but not interesting for the time being. See +# <sys/cdefs.h> for interesting ways that names might be mangled in other +# configurations. + +#include <AvailabilityMacros.h> + +#if MAC_OS_X_VERSION_MIN_REQUIRED != MAC_OS_X_VERSION_10_5 || \ + MAC_OS_X_VERSION_MAX_ALLOWED != MAC_OS_X_VERSION_10_5 || \ + !defined(__i386__) +#error This file only supports 32-bit x86 code with both SDK and DT set to 10.5 +#endif + +#define DEFINE_GLOBAL_SYMBOL(name) \ + .globl name ## ;\ + name ## : + +.text + +# Mac OS X 10.6.8 libclosure-38/runtime.c + +DEFINE_GLOBAL_SYMBOL(__Block_copy) +DEFINE_GLOBAL_SYMBOL(__Block_release) +DEFINE_GLOBAL_SYMBOL(__Block_object_assign) +DEFINE_GLOBAL_SYMBOL(__Block_object_dispose) + +.section __DATA,__data + +# Mac OS X 10.6.8 libclosure-38/data.c + +DEFINE_GLOBAL_SYMBOL(__NSConcreteGlobalBlock) +DEFINE_GLOBAL_SYMBOL(__NSConcreteStackBlock) + +# When this file is in use, the linker is expected to link things against both +# this file and the real copy of libSystem present in the SDK. When doing so, +# the linker is smart enough to produce only one LC_LOAD_DYLIB load command. +# However, it's not smart enough to notice that while this file's dylib only +# provides weak-imported symbols, the real libSystem's dylib does not. +# Consequently, it may produce an LC_LOAD_WEAK_DYLIB load command for +# libSystem instead of an ordinary LC_LOAD_DYLIB command. LC_LOAD_WEAK_DYLIB +# declares that any symbol offered by the library, and in fact the entire +# library, is permitted to be missing at runtime. This is entirely +# inappropriate for libSystem. To counteract this problem, this file also +# defines some other symbols that libSystem provides. Dependents of this +# library are not expected to treat these other symbols as weak imports. In +# order for any dependent that links against this library to load it with an +# LC_LOAD_DYLIB command instead of an LC_LOAD_WEAK_DYLIB command, this library +# must satisfy at least one unresolved non-weak-import symbol required by the +# dependent. + +.text + +# |exit| is a good one: because it's referenced by crt1.o, ordinary executables +# are guaranteed to need this symbol. Unfortunately, there's no such symbol in +# dylib1.o that libSystem is expected to provide, so a few other common libc +# symbols are thrown into the mix. +DEFINE_GLOBAL_SYMBOL(_exit) + +# Include |close| because well-written programs that use the standard library +# are likely to refer to it. Include |open| for good measure because it goes +# pretty well with this. Include the stdio abstractions for these functions +# as well. +DEFINE_GLOBAL_SYMBOL(_close$UNIX2003) +DEFINE_GLOBAL_SYMBOL(_open$UNIX2003) +DEFINE_GLOBAL_SYMBOL(_fclose) +DEFINE_GLOBAL_SYMBOL(_fopen) +DEFINE_GLOBAL_SYMBOL(_fdopen) +DEFINE_GLOBAL_SYMBOL(_freopen$UNIX2003) + +# Commonly-used allocation functions. +DEFINE_GLOBAL_SYMBOL(_malloc) +DEFINE_GLOBAL_SYMBOL(_calloc) +DEFINE_GLOBAL_SYMBOL(_realloc) +DEFINE_GLOBAL_SYMBOL(_reallocf) +DEFINE_GLOBAL_SYMBOL(_valloc) +DEFINE_GLOBAL_SYMBOL(_free) + +# Include |printf|, |fprintf|, |sprintf|, |snprintf|, and |puts|, because +# small test programs are likely to refer to one of these. puts is rarely +# invoked directly, but the compiler may optimize simple printf calls into +# puts calls. +DEFINE_GLOBAL_SYMBOL(_printf) +DEFINE_GLOBAL_SYMBOL(_fprintf) +DEFINE_GLOBAL_SYMBOL(_sprintf) +DEFINE_GLOBAL_SYMBOL(_snprintf) +DEFINE_GLOBAL_SYMBOL(_puts) + +# Some <string.h> functions that are commonly used. +DEFINE_GLOBAL_SYMBOL(_memcmp) +DEFINE_GLOBAL_SYMBOL(_memcpy) +DEFINE_GLOBAL_SYMBOL(_memmove) +DEFINE_GLOBAL_SYMBOL(_memset) +DEFINE_GLOBAL_SYMBOL(_strcasecmp) +DEFINE_GLOBAL_SYMBOL(_strcat) +DEFINE_GLOBAL_SYMBOL(_strchr) +DEFINE_GLOBAL_SYMBOL(_strcmp) +DEFINE_GLOBAL_SYMBOL(_strcpy) +DEFINE_GLOBAL_SYMBOL(_strdup) +DEFINE_GLOBAL_SYMBOL(_strlcat) +DEFINE_GLOBAL_SYMBOL(_strlcpy) +DEFINE_GLOBAL_SYMBOL(_strlen) +DEFINE_GLOBAL_SYMBOL(_strncasecmp) +DEFINE_GLOBAL_SYMBOL(_strncat) +DEFINE_GLOBAL_SYMBOL(_strncmp) +DEFINE_GLOBAL_SYMBOL(_strncpy) +DEFINE_GLOBAL_SYMBOL(_strnstr) +DEFINE_GLOBAL_SYMBOL(_strstr) + +# Some data-section symbols that might be referenced. + +.section __DATA,__data + +DEFINE_GLOBAL_SYMBOL(___stdinp) +DEFINE_GLOBAL_SYMBOL(___stdoutp) +DEFINE_GLOBAL_SYMBOL(___stderrp) + +#undef DEFINE_GLOBAL_SYMBOL diff --git a/content/browser/mac/closure_blocks_leopard_compat.h b/content/browser/mac/closure_blocks_leopard_compat.h new file mode 100644 index 0000000..518c7b1 --- /dev/null +++ b/content/browser/mac/closure_blocks_leopard_compat.h @@ -0,0 +1,104 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_BROWSER_MAC_CLOSURE_BLOCKS_LEOPARD_COMPAT_H_ +#define CONTENT_BROWSER_MAC_CLOSURE_BLOCKS_LEOPARD_COMPAT_H_ +#pragma once + +// libclosure (blocks) compatibility for Mac OS X 10.5 (Leopard) +// +// Background material: +// http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/Blocks +// http://opensource.apple.com/source/libclosure/libclosure-38/ +// +// Leopard doesn't support blocks. Chrome supports Leopard. Chrome needs to use +// blocks. +// +// In any file where you use blocks (any time you type ^{...}), you must +// #include this file to ensure that the runtime symbols referenced by code +// emitted by the compiler are marked for weak-import. This means that if +// these symbols are not present at runtime, the program will still load, but +// their values will be NULL. +// +// In any target (in the GYP sense) where you use blocks, you must also depend +// on the closure_blocks_leopard_compat target to ensure that these symbols +// will be available at link time, even when the 10.5 SDK is in use. This +// allows the continued use of the 10.5 SDK, which does not contain these +// symbols. +// +// This does not relieve you of the responsibility to not use blocks on +// Leopard. Because runtime support for Blocks still isn't present on that +// operating system, the weak-imported symbols will have value 0 and attempts +// to do anything meaningful with them will fail or crash. You must take care +// not to enter any codepath that uses blocks on Leopard. The base::mac::IsOS* +// family may be helpful. +// +// Although this scheme allows the use of the 10.5 SDK and 10.5 runtime in an +// application that uses blocks, it is still necessary to use a compiler that +// supports blocks. GCC 4.2 as shipped with Xcode 3.2 for Mac OS X 10.6 +// qualifies, as do sufficiently recent versions of clang. GCC 4.2 as shipped +// with Xcode 3.1 for Mac OS X 10.5 does not qualify. + +// _NSConcreteGlobalBlock and _NSConcreteStackBlock are private implementation +// details of libclosure defined in libclosure/libclosure-38/Block_private.h, +// but they're exposed from libSystem as public symbols, and the block-enabled +// compiler will emit code that references these symbols. Because the symbols +// aren't present in 10.5's libSystem, they must be declared as weak imports +// in any file that uses blocks. Any block-using file must #include this +// header to guarantee that the symbols will show up in linked output as weak +// imports when compiling for a 10.5 deployment target. Because the symbols +// are always present in 10.6 and higher, they do not need to be a weak +// imports when the deployment target is at least 10.6. +// +// Both GCC and clang emit references to these symbols, providing implicit +// declarations as needed, but respecting any user declaration when present. +// See gcc-5666.3/gcc/c-parser.c build_block_struct_initlist, +// gcc-5666.3/gcc/cp/parser.c build_block_struct_initlist, and +// clang-2.9/lib/CodeGen/CodeGenModule.cpp +// CodeGenModule::getNSConcreteGlobalBlock() and +// CodeGenModule::getNSConcreteStackBlock(). + +#include <AvailabilityMacros.h> + +#if defined(MAC_OS_X_VERSION_10_6) && \ + MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 // SDK >= 10.6 +// Get the system's own declarations of these things if using an SDK where +// they are present. +#include <Block.h> +#endif // SDK >= 10.6 + +extern "C" { + +#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_5 // DT <= 10.5 +#define MAYBE_WEAK_IMPORT __attribute__((weak_import)) +#else // DT > 10.5 +#define MAYBE_WEAK_IMPORT +#endif // DT <= 10.5 + +MAYBE_WEAK_IMPORT extern void* _Block_copy(const void*); +MAYBE_WEAK_IMPORT extern void _Block_release(const void*); +MAYBE_WEAK_IMPORT extern void _Block_object_assign(void*, + const void*, + const int); +MAYBE_WEAK_IMPORT extern void _Block_object_dispose(const void*, const int); + +MAYBE_WEAK_IMPORT extern void* _NSConcreteGlobalBlock[32]; +MAYBE_WEAK_IMPORT extern void* _NSConcreteStackBlock[32]; + +#undef MAYBE_WEAK_IMPORT + +} // extern "C" + +// Macros from <Block.h>, in case <Block.h> is not present. + +#ifndef Block_copy +#define Block_copy(...) \ + ((__typeof(__VA_ARGS__))_Block_copy((const void *)(__VA_ARGS__))) +#endif + +#ifndef Block_release +#define Block_release(...) _Block_release((const void *)(__VA_ARGS__)) +#endif + +#endif // CONTENT_BROWSER_MAC_CLOSURE_BLOCKS_LEOPARD_COMPAT_H_ diff --git a/content/browser/mac/closure_blocks_leopard_compat_unittest.cc b/content/browser/mac/closure_blocks_leopard_compat_unittest.cc new file mode 100644 index 0000000..fd2e467 --- /dev/null +++ b/content/browser/mac/closure_blocks_leopard_compat_unittest.cc @@ -0,0 +1,98 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "testing/gtest/include/gtest/gtest.h" + +#include "base/mac/mac_util.h" +#include "content/browser/mac/closure_blocks_leopard_compat.h" + +// Used in ClosureBlocksLeopardCompatTest.Global. Putting a block at global +// scope results in a block structure whose isa field is set to +// NSConcreteGlobalBlock, ensuring that symbol is referenced. This test needs +// to be able to load on 10.5 where that symbol is not present at runtime, so +// the real test here is that the symbol is weakly imported. If not, the +// executable will fail to load. +void (^global_block)(bool*) = ^(bool* ran_pointer) { *ran_pointer = true; }; + +namespace { + +// It should be possible to declare a block on OSes as early as Leopard +// (10.5). This should be buildable with the 10.5 SDK and a 10.5 deployment +// target, and runnable on 10.5. However, the block itself is not expected to +// be runnable on 10.5. This test verfies that blocks are buildable on 10.5 +// and runnable on Snow Leopard (10.6) and later. + +TEST(ClosureBlocksLeopardCompatTest, Stack) { + bool ran = false; + + // This should result in a block structure whose isa field is set to + // NSConcreteStackBlock, ensuring that symbol is referenced. This test + // needs to be able to load on 10.5 where that symbol is not present at + // runtime, so the real test here checks that the symbol is weakly imported. + // If not, the executable will fail to load. + + void (^test_block)(bool*) = ^(bool* ran_pointer) { *ran_pointer = true; }; + + ASSERT_FALSE(ran); + + if (base::mac::IsOSSnowLeopardOrLater()) { + test_block(&ran); + + EXPECT_TRUE(ran); + } +} + +TEST(ClosureBlocksLeopardCompatTest, Global) { + bool ran = false; + + ASSERT_FALSE(ran); + + if (base::mac::IsOSSnowLeopardOrLater()) { + global_block(&ran); + + EXPECT_TRUE(ran); + } +} + +TEST(ClosureBlocksLeopardCompatTest, CopyRelease) { + if (base::mac::IsOSSnowLeopardOrLater()) { + // Protect the entire test in this conditional, because __block won't run + // on 10.5. + __block int value = 0; + + typedef int (^TestBlockType)(); + TestBlockType local_block = ^(void) { return ++value; }; + + ASSERT_EQ(0, value); + + int rv = local_block(); + EXPECT_EQ(1, rv); + EXPECT_EQ(rv, value); + + // Using Block_copy, Block_release, and these other operations ensures + // that _Block_copy, _Block_release, _Block_object_assign, and + // _Block_object_dispose are referenced. This test needs to be able to + // load on 10.5 where these symbols are not present at runtime, so the + // real test here is that the symbol is weakly imported. If not, the + // executable will fail to load. + + TestBlockType copied_block = Block_copy(local_block); + + rv = copied_block(); + EXPECT_EQ(2, rv); + EXPECT_EQ(rv, value); + + rv = copied_block(); + EXPECT_EQ(3, rv); + EXPECT_EQ(rv, value); + + Block_release(copied_block); + + rv = local_block(); + EXPECT_EQ(4, rv); + EXPECT_EQ(rv, value); + } +} + +} // namespace diff --git a/content/content.gyp b/content/content.gyp index 20b8581..cdc8712 100644 --- a/content/content.gyp +++ b/content/content.gyp @@ -117,6 +117,68 @@ ], }, ], + 'conditions': [ + ['OS=="mac"', { + 'targets': [ + { + 'target_name': 'closure_blocks_leopard_compat', + 'conditions': [ + ['mac_sdk == "10.5"', { + 'type': 'shared_library', + 'product_name': 'closure_blocks_leopard_compat_stub', + 'variables': { + # This target controls stripping directly. See below. + 'mac_strip': 0, + }, + 'sources': [ + 'browser/mac/closure_blocks_leopard_compat.S', + ], + 'xcode_settings': { + # These values are taken from libSystem.dylib in the 10.5 + # SDK. Setting LD_DYLIB_INSTALL_NAME causes anything linked + # against this stub library to look for the symbols it + # provides in the real libSystem at runtime. When using ld + # from Xcode 4 or later (ld64-123.2 and up), giving two + # libraries with the same "install name" to the linker will + # cause it to print "ld: warning: dylibs with same install + # name". This is harmless, and ld will behave as intended + # here. + # + # The real library's compatibility version is used, and the + # value of the current version from the SDK is used to make + # it appear as though anything linked against this stub was + # linked against the real thing. + 'LD_DYLIB_INSTALL_NAME': '/usr/lib/libSystem.B.dylib', + 'DYLIB_COMPATIBILITY_VERSION': '1.0.0', + 'DYLIB_CURRENT_VERSION': '111.1.4', + + # Turn on stripping (yes, even in debug mode), and add the -c + # flag. This is what produces a stub library (MH_DYLIB_STUB) + # as opposed to a dylib (MH_DYLIB). MH_DYLIB_STUB files + # contain symbol tables and everything else needed for + # linking, but are stripped of section contents. This is the + # same way that the stub libraries in Mac OS X SDKs are + # created. dyld will refuse to load a stub library, so this + # provides some insurance in case anyone tries to load the + # stub at runtime. + 'DEPLOYMENT_POSTPROCESSING': 'YES', + 'STRIP_STYLE': 'non-global', + 'STRIPFLAGS': '-c', + }, + }, { # else: mac_sdk != "10.5" + # When using the 10.6 SDK or newer, the necessary definitions + # are already present in libSystem.dylib. There is no need to + # build a stub dylib to provide these symbols at link time. + # This target is still useful to cause those symbols to be + # treated as weak imports in dependents, who still must + # #include closure_blocks_leopard_compat.h to get weak imports. + 'type': 'none', + }], + ], + }, + ], + }], + ], }, { # component != static_library 'target_defaults': { diff --git a/content/content_tests.gypi b/content/content_tests.gypi index fd79b78..5146d05 100644 --- a/content/content_tests.gypi +++ b/content/content_tests.gypi @@ -117,6 +117,7 @@ 'browser/gpu/gpu_blacklist_unittest.cc', 'browser/in_process_webkit/webkit_context_unittest.cc', 'browser/in_process_webkit/webkit_thread_unittest.cc', + 'browser/mac/closure_blocks_leopard_compat_unittest.cc', 'browser/mach_broker_mac_unittest.cc', 'browser/renderer_host/gtk_key_bindings_handler_unittest.cc', 'browser/renderer_host/media/audio_input_device_manager_unittest.cc', @@ -181,6 +182,11 @@ ['exclude', '^browser/renderer_host/gtk_key_bindings_handler_unittest.cc'], ], }], + ['OS=="mac"', { + 'dependencies': [ + 'closure_blocks_leopard_compat', + ], + }], ], }, ], |