Remove base/process/launch* And some unused unittest files. Change-Id: I9900f676c79644cb0fe1a35a4da6857bc5a5b5bf Reviewed-on: https://gn-review.googlesource.com/1620 Commit-Queue: Scott Graham <scottmg@chromium.org> Reviewed-by: Brett Wilson <brettw@chromium.org>
diff --git a/base/linux_util.cc b/base/linux_util.cc index f2d29ec..1f3ae49 100644 --- a/base/linux_util.cc +++ b/base/linux_util.cc
@@ -19,7 +19,6 @@ #include "base/command_line.h" #include "base/files/file_util.h" #include "base/memory/singleton.h" -#include "base/process/launch.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_split.h" #include "base/strings/string_tokenizer.h"
diff --git a/base/mac/bind_objc_block_unittest.mm b/base/mac/bind_objc_block_unittest.mm deleted file mode 100644 index 38da5aa..0000000 --- a/base/mac/bind_objc_block_unittest.mm +++ /dev/null
@@ -1,124 +0,0 @@ -// Copyright (c) 2012 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. - -#import "base/mac/bind_objc_block.h" - -#include <string> - -#include "base/bind.h" -#include "base/callback.h" -#include "base/callback_helpers.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/gtest_mac.h" - -#if defined(OS_IOS) -#include "base/ios/weak_nsobject.h" -#include "base/mac/scoped_nsautorelease_pool.h" -#endif - -namespace { - -TEST(BindObjcBlockTest, TestScopedClosureRunnerExitScope) { - int run_count = 0; - int* ptr = &run_count; - { - base::ScopedClosureRunner runner(base::BindBlock(^{ - (*ptr)++; - })); - EXPECT_EQ(0, run_count); - } - EXPECT_EQ(1, run_count); -} - -TEST(BindObjcBlockTest, TestScopedClosureRunnerRelease) { - int run_count = 0; - int* ptr = &run_count; - base::OnceClosure c; - { - base::ScopedClosureRunner runner(base::BindBlock(^{ - (*ptr)++; - })); - c = runner.Release(); - EXPECT_EQ(0, run_count); - } - EXPECT_EQ(0, run_count); - std::move(c).Run(); - EXPECT_EQ(1, run_count); -} - -TEST(BindObjcBlockTest, TestReturnValue) { - const int kReturnValue = 42; - base::Callback<int(void)> c = base::BindBlock(^{return kReturnValue;}); - EXPECT_EQ(kReturnValue, c.Run()); -} - -TEST(BindObjcBlockTest, TestArgument) { - const int kArgument = 42; - base::Callback<int(int)> c = base::BindBlock(^(int a){return a + 1;}); - EXPECT_EQ(kArgument + 1, c.Run(kArgument)); -} - -TEST(BindObjcBlockTest, TestTwoArguments) { - std::string result; - std::string* ptr = &result; - base::Callback<void(const std::string&, const std::string&)> c = - base::BindBlock(^(const std::string& a, const std::string& b) { - *ptr = a + b; - }); - c.Run("forty", "two"); - EXPECT_EQ(result, "fortytwo"); -} - -TEST(BindObjcBlockTest, TestThreeArguments) { - std::string result; - std::string* ptr = &result; - base::Callback<void(const std::string&, - const std::string&, - const std::string&)> c = - base::BindBlock(^(const std::string& a, - const std::string& b, - const std::string& c) { - *ptr = a + b + c; - }); - c.Run("six", "times", "nine"); - EXPECT_EQ(result, "sixtimesnine"); -} - -TEST(BindObjcBlockTest, TestSixArguments) { - std::string result1; - std::string* ptr = &result1; - int result2; - int* ptr2 = &result2; - base::Callback<void(int, int, const std::string&, const std::string&, - int, const std::string&)> c = - base::BindBlock(^(int a, int b, const std::string& c, - const std::string& d, int e, const std::string& f) { - *ptr = c + d + f; - *ptr2 = a + b + e; - }); - c.Run(1, 2, "infinite", "improbability", 3, "drive"); - EXPECT_EQ(result1, "infiniteimprobabilitydrive"); - EXPECT_EQ(result2, 6); -} - -#if defined(OS_IOS) - -TEST(BindObjcBlockTest, TestBlockReleased) { - base::WeakNSObject<NSObject> weak_nsobject; - { - base::mac::ScopedNSAutoreleasePool autorelease_pool; - NSObject* nsobject = [[[NSObject alloc] init] autorelease]; - weak_nsobject.reset(nsobject); - - auto callback = base::BindBlock(^{ - [nsobject description]; - }); - } - EXPECT_NSEQ(nil, weak_nsobject); -} - -#endif - -} // namespace
diff --git a/base/mac/bind_objc_block_unittest_arc.mm b/base/mac/bind_objc_block_unittest_arc.mm deleted file mode 100644 index f5f953d..0000000 --- a/base/mac/bind_objc_block_unittest_arc.mm +++ /dev/null
@@ -1,125 +0,0 @@ -// Copyright (c) 2012 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. - -#import "base/mac/bind_objc_block.h" - -#include <string> - -#include "base/bind.h" -#include "base/callback.h" -#include "base/callback_helpers.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/gtest_mac.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -namespace { - -TEST(BindObjcBlockTestARC, TestScopedClosureRunnerExitScope) { - int run_count = 0; - int* ptr = &run_count; - { - base::ScopedClosureRunner runner(base::BindBlockArc(^{ - (*ptr)++; - })); - EXPECT_EQ(0, run_count); - } - EXPECT_EQ(1, run_count); -} - -TEST(BindObjcBlockTestARC, TestScopedClosureRunnerRelease) { - int run_count = 0; - int* ptr = &run_count; - base::OnceClosure c; - { - base::ScopedClosureRunner runner(base::BindBlockArc(^{ - (*ptr)++; - })); - c = runner.Release(); - EXPECT_EQ(0, run_count); - } - EXPECT_EQ(0, run_count); - std::move(c).Run(); - EXPECT_EQ(1, run_count); -} - -TEST(BindObjcBlockTestARC, TestReturnValue) { - const int kReturnValue = 42; - base::Callback<int(void)> c = base::BindBlockArc(^{ - return kReturnValue; - }); - EXPECT_EQ(kReturnValue, c.Run()); -} - -TEST(BindObjcBlockTestARC, TestArgument) { - const int kArgument = 42; - base::Callback<int(int)> c = base::BindBlockArc(^(int a) { - return a + 1; - }); - EXPECT_EQ(kArgument + 1, c.Run(kArgument)); -} - -TEST(BindObjcBlockTestARC, TestTwoArguments) { - std::string result; - std::string* ptr = &result; - base::Callback<void(const std::string&, const std::string&)> c = - base::BindBlockArc(^(const std::string& a, const std::string& b) { - *ptr = a + b; - }); - c.Run("forty", "two"); - EXPECT_EQ(result, "fortytwo"); -} - -TEST(BindObjcBlockTestARC, TestThreeArguments) { - std::string result; - std::string* ptr = &result; - base::Callback<void(const std::string&, const std::string&, - const std::string&)> - c = base::BindBlockArc( - ^(const std::string& a, const std::string& b, const std::string& c) { - *ptr = a + b + c; - }); - c.Run("six", "times", "nine"); - EXPECT_EQ(result, "sixtimesnine"); -} - -TEST(BindObjcBlockTestARC, TestSixArguments) { - std::string result1; - std::string* ptr = &result1; - int result2; - int* ptr2 = &result2; - base::Callback<void(int, int, const std::string&, const std::string&, int, - const std::string&)> - c = base::BindBlockArc(^(int a, int b, const std::string& c, - const std::string& d, int e, - const std::string& f) { - *ptr = c + d + f; - *ptr2 = a + b + e; - }); - c.Run(1, 2, "infinite", "improbability", 3, "drive"); - EXPECT_EQ(result1, "infiniteimprobabilitydrive"); - EXPECT_EQ(result2, 6); -} - -#if defined(OS_IOS) - -TEST(BindObjcBlockTestARC, TestBlockReleased) { - __weak NSObject* weak_nsobject; - @autoreleasepool { - NSObject* nsobject = [[NSObject alloc] init]; - weak_nsobject = nsobject; - - auto callback = base::BindBlockArc(^{ - [nsobject description]; - }); - } - EXPECT_NSEQ(nil, weak_nsobject); -} - -#endif - -} // namespace
diff --git a/base/mac/call_with_eh_frame_unittest.mm b/base/mac/call_with_eh_frame_unittest.mm deleted file mode 100644 index 4dad822..0000000 --- a/base/mac/call_with_eh_frame_unittest.mm +++ /dev/null
@@ -1,55 +0,0 @@ -// Copyright 2015 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 "base/mac/call_with_eh_frame.h" - -#import <Foundation/Foundation.h> - -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { -namespace mac { -namespace { - -class CallWithEHFrameTest : public testing::Test { - protected: - void ThrowException() { - @throw [NSException exceptionWithName:@"TestException" - reason:@"Testing exceptions" - userInfo:nil]; - } -}; - -// Catching from within the EHFrame is allowed. -TEST_F(CallWithEHFrameTest, CatchExceptionHigher) { - bool __block saw_exception = false; - base::mac::CallWithEHFrame(^{ - @try { - ThrowException(); - } @catch (NSException* exception) { - saw_exception = true; - } - }); - EXPECT_TRUE(saw_exception); -} - -// Trying to catch an exception outside the EHFrame is blocked. -TEST_F(CallWithEHFrameTest, CatchExceptionLower) { - auto catch_exception_lower = ^{ - bool saw_exception = false; - @try { - base::mac::CallWithEHFrame(^{ - ThrowException(); - }); - } @catch (NSException* exception) { - saw_exception = true; - } - ASSERT_FALSE(saw_exception); - }; - EXPECT_DEATH(catch_exception_lower(), ""); -} - -} // namespace -} // namespace mac -} // namespace base
diff --git a/base/mac/foundation_util_unittest.mm b/base/mac/foundation_util_unittest.mm deleted file mode 100644 index ce02163..0000000 --- a/base/mac/foundation_util_unittest.mm +++ /dev/null
@@ -1,405 +0,0 @@ -// Copyright (c) 2012 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 "base/mac/foundation_util.h" - -#include <limits.h> -#include <stddef.h> - -#include "base/compiler_specific.h" -#include "base/files/file_path.h" -#include "base/format_macros.h" -#include "base/mac/scoped_cftyperef.h" -#include "base/mac/scoped_nsautorelease_pool.h" -#include "base/macros.h" -#include "base/strings/stringprintf.h" -#include "build_config.h" -#include "testing/gtest/include/gtest/gtest.h" -#import "testing/gtest_mac.h" - -namespace base { -namespace mac { - -TEST(FoundationUtilTest, CFCast) { - // Build out the CF types to be tested as empty containers. - ScopedCFTypeRef<CFTypeRef> test_array( - CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks)); - ScopedCFTypeRef<CFTypeRef> test_array_mutable( - CFArrayCreateMutable(NULL, 0, &kCFTypeArrayCallBacks)); - ScopedCFTypeRef<CFTypeRef> test_bag( - CFBagCreate(NULL, NULL, 0, &kCFTypeBagCallBacks)); - ScopedCFTypeRef<CFTypeRef> test_bag_mutable( - CFBagCreateMutable(NULL, 0, &kCFTypeBagCallBacks)); - CFTypeRef test_bool = kCFBooleanTrue; - ScopedCFTypeRef<CFTypeRef> test_data( - CFDataCreate(NULL, NULL, 0)); - ScopedCFTypeRef<CFTypeRef> test_data_mutable( - CFDataCreateMutable(NULL, 0)); - ScopedCFTypeRef<CFTypeRef> test_date( - CFDateCreate(NULL, 0)); - ScopedCFTypeRef<CFTypeRef> test_dict( - CFDictionaryCreate(NULL, NULL, NULL, 0, - &kCFCopyStringDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)); - ScopedCFTypeRef<CFTypeRef> test_dict_mutable( - CFDictionaryCreateMutable(NULL, 0, - &kCFCopyStringDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)); - int int_val = 256; - ScopedCFTypeRef<CFTypeRef> test_number( - CFNumberCreate(NULL, kCFNumberIntType, &int_val)); - CFTypeRef test_null = kCFNull; - ScopedCFTypeRef<CFTypeRef> test_set( - CFSetCreate(NULL, NULL, 0, &kCFTypeSetCallBacks)); - ScopedCFTypeRef<CFTypeRef> test_set_mutable( - CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks)); - ScopedCFTypeRef<CFTypeRef> test_str( - CFStringCreateWithBytes(NULL, NULL, 0, kCFStringEncodingASCII, false)); - CFTypeRef test_str_const = CFSTR("hello"); - ScopedCFTypeRef<CFTypeRef> test_str_mutable(CFStringCreateMutable(NULL, 0)); - - // Make sure the allocations of CF types are good. - EXPECT_TRUE(test_array); - EXPECT_TRUE(test_array_mutable); - EXPECT_TRUE(test_bag); - EXPECT_TRUE(test_bag_mutable); - EXPECT_TRUE(test_bool); - EXPECT_TRUE(test_data); - EXPECT_TRUE(test_data_mutable); - EXPECT_TRUE(test_date); - EXPECT_TRUE(test_dict); - EXPECT_TRUE(test_dict_mutable); - EXPECT_TRUE(test_number); - EXPECT_TRUE(test_null); - EXPECT_TRUE(test_set); - EXPECT_TRUE(test_set_mutable); - EXPECT_TRUE(test_str); - EXPECT_TRUE(test_str_const); - EXPECT_TRUE(test_str_mutable); - - // Casting the CFTypeRef objects correctly provides the same pointer. - EXPECT_EQ(test_array, CFCast<CFArrayRef>(test_array)); - EXPECT_EQ(test_array_mutable, CFCast<CFArrayRef>(test_array_mutable)); - EXPECT_EQ(test_bag, CFCast<CFBagRef>(test_bag)); - EXPECT_EQ(test_bag_mutable, CFCast<CFBagRef>(test_bag_mutable)); - EXPECT_EQ(test_bool, CFCast<CFBooleanRef>(test_bool)); - EXPECT_EQ(test_data, CFCast<CFDataRef>(test_data)); - EXPECT_EQ(test_data_mutable, CFCast<CFDataRef>(test_data_mutable)); - EXPECT_EQ(test_date, CFCast<CFDateRef>(test_date)); - EXPECT_EQ(test_dict, CFCast<CFDictionaryRef>(test_dict)); - EXPECT_EQ(test_dict_mutable, CFCast<CFDictionaryRef>(test_dict_mutable)); - EXPECT_EQ(test_number, CFCast<CFNumberRef>(test_number)); - EXPECT_EQ(test_null, CFCast<CFNullRef>(test_null)); - EXPECT_EQ(test_set, CFCast<CFSetRef>(test_set)); - EXPECT_EQ(test_set_mutable, CFCast<CFSetRef>(test_set_mutable)); - EXPECT_EQ(test_str, CFCast<CFStringRef>(test_str)); - EXPECT_EQ(test_str_const, CFCast<CFStringRef>(test_str_const)); - EXPECT_EQ(test_str_mutable, CFCast<CFStringRef>(test_str_mutable)); - - // When given an incorrect CF cast, provide NULL. - EXPECT_FALSE(CFCast<CFStringRef>(test_array)); - EXPECT_FALSE(CFCast<CFStringRef>(test_array_mutable)); - EXPECT_FALSE(CFCast<CFStringRef>(test_bag)); - EXPECT_FALSE(CFCast<CFSetRef>(test_bag_mutable)); - EXPECT_FALSE(CFCast<CFSetRef>(test_bool)); - EXPECT_FALSE(CFCast<CFNullRef>(test_data)); - EXPECT_FALSE(CFCast<CFDictionaryRef>(test_data_mutable)); - EXPECT_FALSE(CFCast<CFDictionaryRef>(test_date)); - EXPECT_FALSE(CFCast<CFNumberRef>(test_dict)); - EXPECT_FALSE(CFCast<CFDateRef>(test_dict_mutable)); - EXPECT_FALSE(CFCast<CFDataRef>(test_number)); - EXPECT_FALSE(CFCast<CFDataRef>(test_null)); - EXPECT_FALSE(CFCast<CFBooleanRef>(test_set)); - EXPECT_FALSE(CFCast<CFBagRef>(test_set_mutable)); - EXPECT_FALSE(CFCast<CFBagRef>(test_str)); - EXPECT_FALSE(CFCast<CFArrayRef>(test_str_const)); - EXPECT_FALSE(CFCast<CFArrayRef>(test_str_mutable)); - - // Giving a NULL provides a NULL. - EXPECT_FALSE(CFCast<CFArrayRef>(NULL)); - EXPECT_FALSE(CFCast<CFBagRef>(NULL)); - EXPECT_FALSE(CFCast<CFBooleanRef>(NULL)); - EXPECT_FALSE(CFCast<CFDataRef>(NULL)); - EXPECT_FALSE(CFCast<CFDateRef>(NULL)); - EXPECT_FALSE(CFCast<CFDictionaryRef>(NULL)); - EXPECT_FALSE(CFCast<CFNullRef>(NULL)); - EXPECT_FALSE(CFCast<CFNumberRef>(NULL)); - EXPECT_FALSE(CFCast<CFSetRef>(NULL)); - EXPECT_FALSE(CFCast<CFStringRef>(NULL)); - - // CFCastStrict: correct cast results in correct pointer being returned. - EXPECT_EQ(test_array, CFCastStrict<CFArrayRef>(test_array)); - EXPECT_EQ(test_array_mutable, CFCastStrict<CFArrayRef>(test_array_mutable)); - EXPECT_EQ(test_bag, CFCastStrict<CFBagRef>(test_bag)); - EXPECT_EQ(test_bag_mutable, CFCastStrict<CFBagRef>(test_bag_mutable)); - EXPECT_EQ(test_bool, CFCastStrict<CFBooleanRef>(test_bool)); - EXPECT_EQ(test_data, CFCastStrict<CFDataRef>(test_data)); - EXPECT_EQ(test_data_mutable, CFCastStrict<CFDataRef>(test_data_mutable)); - EXPECT_EQ(test_date, CFCastStrict<CFDateRef>(test_date)); - EXPECT_EQ(test_dict, CFCastStrict<CFDictionaryRef>(test_dict)); - EXPECT_EQ(test_dict_mutable, - CFCastStrict<CFDictionaryRef>(test_dict_mutable)); - EXPECT_EQ(test_number, CFCastStrict<CFNumberRef>(test_number)); - EXPECT_EQ(test_null, CFCastStrict<CFNullRef>(test_null)); - EXPECT_EQ(test_set, CFCastStrict<CFSetRef>(test_set)); - EXPECT_EQ(test_set_mutable, CFCastStrict<CFSetRef>(test_set_mutable)); - EXPECT_EQ(test_str, CFCastStrict<CFStringRef>(test_str)); - EXPECT_EQ(test_str_const, CFCastStrict<CFStringRef>(test_str_const)); - EXPECT_EQ(test_str_mutable, CFCastStrict<CFStringRef>(test_str_mutable)); - - // CFCastStrict: Giving a NULL provides a NULL. - EXPECT_FALSE(CFCastStrict<CFArrayRef>(NULL)); - EXPECT_FALSE(CFCastStrict<CFBagRef>(NULL)); - EXPECT_FALSE(CFCastStrict<CFBooleanRef>(NULL)); - EXPECT_FALSE(CFCastStrict<CFDataRef>(NULL)); - EXPECT_FALSE(CFCastStrict<CFDateRef>(NULL)); - EXPECT_FALSE(CFCastStrict<CFDictionaryRef>(NULL)); - EXPECT_FALSE(CFCastStrict<CFNullRef>(NULL)); - EXPECT_FALSE(CFCastStrict<CFNumberRef>(NULL)); - EXPECT_FALSE(CFCastStrict<CFSetRef>(NULL)); - EXPECT_FALSE(CFCastStrict<CFStringRef>(NULL)); -} - -TEST(FoundationUtilTest, ObjCCast) { - ScopedNSAutoreleasePool pool; - - id test_array = @[]; - id test_array_mutable = [NSMutableArray array]; - id test_data = [NSData data]; - id test_data_mutable = [NSMutableData dataWithCapacity:10]; - id test_date = [NSDate date]; - id test_dict = @{ @"meaning" : @42 }; - id test_dict_mutable = [NSMutableDictionary dictionaryWithCapacity:10]; - id test_number = @42; - id test_null = [NSNull null]; - id test_set = [NSSet setWithObject:@"string object"]; - id test_set_mutable = [NSMutableSet setWithCapacity:10]; - id test_str = [NSString string]; - id test_str_const = @"bonjour"; - id test_str_mutable = [NSMutableString stringWithCapacity:10]; - - // Make sure the allocations of NS types are good. - EXPECT_TRUE(test_array); - EXPECT_TRUE(test_array_mutable); - EXPECT_TRUE(test_data); - EXPECT_TRUE(test_data_mutable); - EXPECT_TRUE(test_date); - EXPECT_TRUE(test_dict); - EXPECT_TRUE(test_dict_mutable); - EXPECT_TRUE(test_number); - EXPECT_TRUE(test_null); - EXPECT_TRUE(test_set); - EXPECT_TRUE(test_set_mutable); - EXPECT_TRUE(test_str); - EXPECT_TRUE(test_str_const); - EXPECT_TRUE(test_str_mutable); - - // Casting the id correctly provides the same pointer. - EXPECT_EQ(test_array, ObjCCast<NSArray>(test_array)); - EXPECT_EQ(test_array_mutable, ObjCCast<NSArray>(test_array_mutable)); - EXPECT_EQ(test_data, ObjCCast<NSData>(test_data)); - EXPECT_EQ(test_data_mutable, ObjCCast<NSData>(test_data_mutable)); - EXPECT_EQ(test_date, ObjCCast<NSDate>(test_date)); - EXPECT_EQ(test_dict, ObjCCast<NSDictionary>(test_dict)); - EXPECT_EQ(test_dict_mutable, ObjCCast<NSDictionary>(test_dict_mutable)); - EXPECT_EQ(test_number, ObjCCast<NSNumber>(test_number)); - EXPECT_EQ(test_null, ObjCCast<NSNull>(test_null)); - EXPECT_EQ(test_set, ObjCCast<NSSet>(test_set)); - EXPECT_EQ(test_set_mutable, ObjCCast<NSSet>(test_set_mutable)); - EXPECT_EQ(test_str, ObjCCast<NSString>(test_str)); - EXPECT_EQ(test_str_const, ObjCCast<NSString>(test_str_const)); - EXPECT_EQ(test_str_mutable, ObjCCast<NSString>(test_str_mutable)); - - // When given an incorrect ObjC cast, provide nil. - EXPECT_FALSE(ObjCCast<NSString>(test_array)); - EXPECT_FALSE(ObjCCast<NSString>(test_array_mutable)); - EXPECT_FALSE(ObjCCast<NSString>(test_data)); - EXPECT_FALSE(ObjCCast<NSString>(test_data_mutable)); - EXPECT_FALSE(ObjCCast<NSSet>(test_date)); - EXPECT_FALSE(ObjCCast<NSSet>(test_dict)); - EXPECT_FALSE(ObjCCast<NSNumber>(test_dict_mutable)); - EXPECT_FALSE(ObjCCast<NSNull>(test_number)); - EXPECT_FALSE(ObjCCast<NSDictionary>(test_null)); - EXPECT_FALSE(ObjCCast<NSDictionary>(test_set)); - EXPECT_FALSE(ObjCCast<NSDate>(test_set_mutable)); - EXPECT_FALSE(ObjCCast<NSData>(test_str)); - EXPECT_FALSE(ObjCCast<NSData>(test_str_const)); - EXPECT_FALSE(ObjCCast<NSArray>(test_str_mutable)); - - // Giving a nil provides a nil. - EXPECT_FALSE(ObjCCast<NSArray>(nil)); - EXPECT_FALSE(ObjCCast<NSData>(nil)); - EXPECT_FALSE(ObjCCast<NSDate>(nil)); - EXPECT_FALSE(ObjCCast<NSDictionary>(nil)); - EXPECT_FALSE(ObjCCast<NSNull>(nil)); - EXPECT_FALSE(ObjCCast<NSNumber>(nil)); - EXPECT_FALSE(ObjCCast<NSSet>(nil)); - EXPECT_FALSE(ObjCCast<NSString>(nil)); - - // ObjCCastStrict: correct cast results in correct pointer being returned. - EXPECT_EQ(test_array, ObjCCastStrict<NSArray>(test_array)); - EXPECT_EQ(test_array_mutable, - ObjCCastStrict<NSArray>(test_array_mutable)); - EXPECT_EQ(test_data, ObjCCastStrict<NSData>(test_data)); - EXPECT_EQ(test_data_mutable, - ObjCCastStrict<NSData>(test_data_mutable)); - EXPECT_EQ(test_date, ObjCCastStrict<NSDate>(test_date)); - EXPECT_EQ(test_dict, ObjCCastStrict<NSDictionary>(test_dict)); - EXPECT_EQ(test_dict_mutable, - ObjCCastStrict<NSDictionary>(test_dict_mutable)); - EXPECT_EQ(test_number, ObjCCastStrict<NSNumber>(test_number)); - EXPECT_EQ(test_null, ObjCCastStrict<NSNull>(test_null)); - EXPECT_EQ(test_set, ObjCCastStrict<NSSet>(test_set)); - EXPECT_EQ(test_set_mutable, - ObjCCastStrict<NSSet>(test_set_mutable)); - EXPECT_EQ(test_str, ObjCCastStrict<NSString>(test_str)); - EXPECT_EQ(test_str_const, - ObjCCastStrict<NSString>(test_str_const)); - EXPECT_EQ(test_str_mutable, - ObjCCastStrict<NSString>(test_str_mutable)); - - // ObjCCastStrict: Giving a nil provides a nil. - EXPECT_FALSE(ObjCCastStrict<NSArray>(nil)); - EXPECT_FALSE(ObjCCastStrict<NSData>(nil)); - EXPECT_FALSE(ObjCCastStrict<NSDate>(nil)); - EXPECT_FALSE(ObjCCastStrict<NSDictionary>(nil)); - EXPECT_FALSE(ObjCCastStrict<NSNull>(nil)); - EXPECT_FALSE(ObjCCastStrict<NSNumber>(nil)); - EXPECT_FALSE(ObjCCastStrict<NSSet>(nil)); - EXPECT_FALSE(ObjCCastStrict<NSString>(nil)); -} - -TEST(FoundationUtilTest, GetValueFromDictionary) { - int one = 1, two = 2, three = 3; - - ScopedCFTypeRef<CFNumberRef> cf_one( - CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &one)); - ScopedCFTypeRef<CFNumberRef> cf_two( - CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &two)); - ScopedCFTypeRef<CFNumberRef> cf_three( - CFNumberCreate(kCFAllocatorDefault, kCFNumberIntType, &three)); - - CFStringRef keys[] = { CFSTR("one"), CFSTR("two"), CFSTR("three") }; - CFNumberRef values[] = { cf_one, cf_two, cf_three }; - - static_assert(arraysize(keys) == arraysize(values), - "keys and values arrays must have the same size"); - - ScopedCFTypeRef<CFDictionaryRef> test_dict( - CFDictionaryCreate(kCFAllocatorDefault, - reinterpret_cast<const void**>(keys), - reinterpret_cast<const void**>(values), - arraysize(values), - &kCFCopyStringDictionaryKeyCallBacks, - &kCFTypeDictionaryValueCallBacks)); - - // GetValueFromDictionary<>(_, _) should produce the correct - // expected output. - EXPECT_EQ(values[0], - GetValueFromDictionary<CFNumberRef>(test_dict, CFSTR("one"))); - EXPECT_EQ(values[1], - GetValueFromDictionary<CFNumberRef>(test_dict, CFSTR("two"))); - EXPECT_EQ(values[2], - GetValueFromDictionary<CFNumberRef>(test_dict, CFSTR("three"))); - - // Bad input should produce bad output. - EXPECT_FALSE(GetValueFromDictionary<CFNumberRef>(test_dict, CFSTR("four"))); - EXPECT_FALSE(GetValueFromDictionary<CFStringRef>(test_dict, CFSTR("one"))); -} - -TEST(FoundationUtilTest, FilePathToNSString) { - EXPECT_NSEQ(nil, FilePathToNSString(FilePath())); - EXPECT_NSEQ(@"/a/b", FilePathToNSString(FilePath("/a/b"))); -} - -TEST(FoundationUtilTest, NSStringToFilePath) { - EXPECT_EQ(FilePath(), NSStringToFilePath(nil)); - EXPECT_EQ(FilePath(), NSStringToFilePath(@"")); - EXPECT_EQ(FilePath("/a/b"), NSStringToFilePath(@"/a/b")); -} - -TEST(FoundationUtilTest, CFRangeToNSRange) { - NSRange range_out; - EXPECT_TRUE(CFRangeToNSRange(CFRangeMake(10, 5), &range_out)); - EXPECT_EQ(10UL, range_out.location); - EXPECT_EQ(5UL, range_out.length); - EXPECT_FALSE(CFRangeToNSRange(CFRangeMake(-1, 5), &range_out)); - EXPECT_FALSE(CFRangeToNSRange(CFRangeMake(5, -1), &range_out)); - EXPECT_FALSE(CFRangeToNSRange(CFRangeMake(-1, -1), &range_out)); - EXPECT_FALSE(CFRangeToNSRange(CFRangeMake(LONG_MAX, LONG_MAX), &range_out)); - EXPECT_FALSE(CFRangeToNSRange(CFRangeMake(LONG_MIN, LONG_MAX), &range_out)); -} - -TEST(StringNumberConversionsTest, FormatNSInteger) { - // The PRI[dxu]NS macro assumes that NSInteger is a typedef to "int" on - // 32-bit architecture and a typedef to "long" on 64-bit architecture - // (respectively "unsigned int" and "unsigned long" for NSUInteger). Use - // pointer incompatibility to validate this at compilation. -#if defined(ARCH_CPU_64_BITS) - typedef long FormatNSIntegerAsType; - typedef unsigned long FormatNSUIntegerAsType; -#else - typedef int FormatNSIntegerAsType; - typedef unsigned int FormatNSUIntegerAsType; -#endif // defined(ARCH_CPU_64_BITS) - - NSInteger some_nsinteger; - FormatNSIntegerAsType* pointer_to_some_nsinteger = &some_nsinteger; - ALLOW_UNUSED_LOCAL(pointer_to_some_nsinteger); - - NSUInteger some_nsuinteger; - FormatNSUIntegerAsType* pointer_to_some_nsuinteger = &some_nsuinteger; - ALLOW_UNUSED_LOCAL(pointer_to_some_nsuinteger); - - // Check that format specifier works correctly for NSInteger. - const struct { - NSInteger value; - const char* expected; - const char* expected_hex; - } nsinteger_cases[] = { -#if !defined(ARCH_CPU_64_BITS) - {12345678, "12345678", "bc614e"}, - {-12345678, "-12345678", "ff439eb2"}, -#else - {12345678, "12345678", "bc614e"}, - {-12345678, "-12345678", "ffffffffff439eb2"}, - {137451299150l, "137451299150", "2000bc614e"}, - {-137451299150l, "-137451299150", "ffffffdfff439eb2"}, -#endif // !defined(ARCH_CPU_64_BITS) - }; - - for (size_t i = 0; i < arraysize(nsinteger_cases); ++i) { - EXPECT_EQ(nsinteger_cases[i].expected, - StringPrintf("%" PRIdNS, nsinteger_cases[i].value)); - EXPECT_EQ(nsinteger_cases[i].expected_hex, - StringPrintf("%" PRIxNS, nsinteger_cases[i].value)); - } - - // Check that format specifier works correctly for NSUInteger. - const struct { - NSUInteger value; - const char* expected; - const char* expected_hex; - } nsuinteger_cases[] = { -#if !defined(ARCH_CPU_64_BITS) - {12345678u, "12345678", "bc614e"}, - {4282621618u, "4282621618", "ff439eb2"}, -#else - {12345678u, "12345678", "bc614e"}, - {4282621618u, "4282621618", "ff439eb2"}, - {137451299150ul, "137451299150", "2000bc614e"}, - {18446743936258252466ul, "18446743936258252466", "ffffffdfff439eb2"}, -#endif // !defined(ARCH_CPU_64_BITS) - }; - - for (size_t i = 0; i < arraysize(nsuinteger_cases); ++i) { - EXPECT_EQ(nsuinteger_cases[i].expected, - StringPrintf("%" PRIuNS, nsuinteger_cases[i].value)); - EXPECT_EQ(nsuinteger_cases[i].expected_hex, - StringPrintf("%" PRIxNS, nsuinteger_cases[i].value)); - } -} - -} // namespace mac -} // namespace base
diff --git a/base/mac/mac_util_unittest.mm b/base/mac/mac_util_unittest.mm deleted file mode 100644 index 266d1c4..0000000 --- a/base/mac/mac_util_unittest.mm +++ /dev/null
@@ -1,299 +0,0 @@ -// Copyright (c) 2012 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. - -#import <Cocoa/Cocoa.h> -#include <stddef.h> -#include <stdint.h> - -#include "base/mac/mac_util.h" - -#include "base/files/file_path.h" -#include "base/files/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/mac/foundation_util.h" -#include "base/mac/scoped_cftyperef.h" -#include "base/mac/scoped_nsobject.h" -#include "base/macros.h" -#include "base/sys_info.h" -#include "testing/gtest/include/gtest/gtest.h" -#include "testing/platform_test.h" - -#include <errno.h> -#include <sys/xattr.h> - -namespace base { -namespace mac { - -namespace { - -typedef PlatformTest MacUtilTest; - -TEST_F(MacUtilTest, GetUserDirectoryTest) { - // Try a few keys, make sure they come back with non-empty paths. - FilePath caches_dir; - EXPECT_TRUE(GetUserDirectory(NSCachesDirectory, &caches_dir)); - EXPECT_FALSE(caches_dir.empty()); - - FilePath application_support_dir; - EXPECT_TRUE(GetUserDirectory(NSApplicationSupportDirectory, - &application_support_dir)); - EXPECT_FALSE(application_support_dir.empty()); - - FilePath library_dir; - EXPECT_TRUE(GetUserDirectory(NSLibraryDirectory, &library_dir)); - EXPECT_FALSE(library_dir.empty()); -} - -TEST_F(MacUtilTest, TestLibraryPath) { - FilePath library_dir = GetUserLibraryPath(); - // Make sure the string isn't empty. - EXPECT_FALSE(library_dir.value().empty()); -} - -TEST_F(MacUtilTest, TestGetAppBundlePath) { - FilePath out; - - // Make sure it doesn't crash. - out = GetAppBundlePath(FilePath()); - EXPECT_TRUE(out.empty()); - - // Some more invalid inputs. - const char* const invalid_inputs[] = { - "/", "/foo", "foo", "/foo/bar.", "foo/bar.", "/foo/bar./bazquux", - "foo/bar./bazquux", "foo/.app", "//foo", - }; - for (size_t i = 0; i < arraysize(invalid_inputs); i++) { - out = GetAppBundlePath(FilePath(invalid_inputs[i])); - EXPECT_TRUE(out.empty()) << "loop: " << i; - } - - // Some valid inputs; this and |expected_outputs| should be in sync. - struct { - const char *in; - const char *expected_out; - } valid_inputs[] = { - { "FooBar.app/", "FooBar.app" }, - { "/FooBar.app", "/FooBar.app" }, - { "/FooBar.app/", "/FooBar.app" }, - { "//FooBar.app", "//FooBar.app" }, - { "/Foo/Bar.app", "/Foo/Bar.app" }, - { "/Foo/Bar.app/", "/Foo/Bar.app" }, - { "/F/B.app", "/F/B.app" }, - { "/F/B.app/", "/F/B.app" }, - { "/Foo/Bar.app/baz", "/Foo/Bar.app" }, - { "/Foo/Bar.app/baz/", "/Foo/Bar.app" }, - { "/Foo/Bar.app/baz/quux.app/quuux", "/Foo/Bar.app" }, - { "/Applications/Google Foo.app/bar/Foo Helper.app/quux/Foo Helper", - "/Applications/Google Foo.app" }, - }; - for (size_t i = 0; i < arraysize(valid_inputs); i++) { - out = GetAppBundlePath(FilePath(valid_inputs[i].in)); - EXPECT_FALSE(out.empty()) << "loop: " << i; - EXPECT_STREQ(valid_inputs[i].expected_out, - out.value().c_str()) << "loop: " << i; - } -} - -// http://crbug.com/425745 -TEST_F(MacUtilTest, DISABLED_TestExcludeFileFromBackups) { - // The file must already exist in order to set its exclusion property. - ScopedTempDir temp_dir_; - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - FilePath dummy_file_path = temp_dir_.GetPath().Append("DummyFile"); - const char dummy_data[] = "All your base are belong to us!"; - // Dump something real into the file. - ASSERT_EQ(static_cast<int>(arraysize(dummy_data)), - WriteFile(dummy_file_path, dummy_data, arraysize(dummy_data))); - NSString* fileURLString = - [NSString stringWithUTF8String:dummy_file_path.value().c_str()]; - NSURL* fileURL = [NSURL URLWithString:fileURLString]; - // Initial state should be non-excluded. - EXPECT_FALSE(CSBackupIsItemExcluded(base::mac::NSToCFCast(fileURL), NULL)); - // Exclude the file. - EXPECT_TRUE(SetFileBackupExclusion(dummy_file_path)); - // SetFileBackupExclusion never excludes by path. - Boolean excluded_by_path = FALSE; - Boolean excluded = - CSBackupIsItemExcluded(base::mac::NSToCFCast(fileURL), &excluded_by_path); - EXPECT_TRUE(excluded); - EXPECT_FALSE(excluded_by_path); -} - -TEST_F(MacUtilTest, NSObjectRetainRelease) { - base::scoped_nsobject<NSArray> array( - [[NSArray alloc] initWithObjects:@"foo", nil]); - EXPECT_EQ(1U, [array retainCount]); - - NSObjectRetain(array); - EXPECT_EQ(2U, [array retainCount]); - - NSObjectRelease(array); - EXPECT_EQ(1U, [array retainCount]); -} - -TEST_F(MacUtilTest, IsOSEllipsis) { - int32_t major, minor, bugfix; - base::SysInfo::OperatingSystemVersionNumbers(&major, &minor, &bugfix); - - if (major == 10) { - if (minor == 9) { - EXPECT_TRUE(IsOS10_9()); - EXPECT_TRUE(IsAtMostOS10_9()); - EXPECT_TRUE(IsAtLeastOS10_9()); - EXPECT_FALSE(IsOS10_10()); - EXPECT_TRUE(IsAtMostOS10_10()); - EXPECT_FALSE(IsAtLeastOS10_10()); - EXPECT_FALSE(IsOS10_11()); - EXPECT_TRUE(IsAtMostOS10_11()); - EXPECT_FALSE(IsAtLeastOS10_11()); - EXPECT_FALSE(IsOS10_12()); - EXPECT_FALSE(IsAtLeastOS10_12()); - EXPECT_TRUE(IsAtMostOS10_12()); - EXPECT_FALSE(IsOS10_13()); - EXPECT_FALSE(IsAtLeastOS10_13()); - EXPECT_TRUE(IsAtMostOS10_13()); - EXPECT_FALSE(IsOSLaterThan10_13_DontCallThis()); - } else if (minor == 10) { - EXPECT_FALSE(IsOS10_9()); - EXPECT_FALSE(IsAtMostOS10_9()); - EXPECT_TRUE(IsAtLeastOS10_9()); - EXPECT_TRUE(IsOS10_10()); - EXPECT_TRUE(IsAtMostOS10_10()); - EXPECT_TRUE(IsAtLeastOS10_10()); - EXPECT_FALSE(IsOS10_11()); - EXPECT_TRUE(IsAtMostOS10_11()); - EXPECT_FALSE(IsAtLeastOS10_11()); - EXPECT_FALSE(IsOS10_12()); - EXPECT_FALSE(IsAtLeastOS10_12()); - EXPECT_TRUE(IsAtMostOS10_12()); - EXPECT_FALSE(IsOS10_13()); - EXPECT_FALSE(IsAtLeastOS10_13()); - EXPECT_TRUE(IsAtMostOS10_13()); - EXPECT_FALSE(IsOSLaterThan10_13_DontCallThis()); - } else if (minor == 11) { - EXPECT_FALSE(IsOS10_9()); - EXPECT_FALSE(IsAtMostOS10_9()); - EXPECT_TRUE(IsAtLeastOS10_9()); - EXPECT_FALSE(IsOS10_10()); - EXPECT_FALSE(IsAtMostOS10_10()); - EXPECT_TRUE(IsAtLeastOS10_10()); - EXPECT_TRUE(IsOS10_11()); - EXPECT_TRUE(IsAtMostOS10_11()); - EXPECT_TRUE(IsAtLeastOS10_11()); - EXPECT_FALSE(IsOS10_12()); - EXPECT_FALSE(IsAtLeastOS10_12()); - EXPECT_TRUE(IsAtMostOS10_12()); - EXPECT_FALSE(IsOS10_13()); - EXPECT_FALSE(IsAtLeastOS10_13()); - EXPECT_TRUE(IsAtMostOS10_13()); - EXPECT_FALSE(IsOSLaterThan10_13_DontCallThis()); - } else if (minor == 12) { - EXPECT_FALSE(IsOS10_9()); - EXPECT_FALSE(IsAtMostOS10_9()); - EXPECT_TRUE(IsAtLeastOS10_9()); - EXPECT_FALSE(IsOS10_10()); - EXPECT_FALSE(IsAtMostOS10_10()); - EXPECT_TRUE(IsAtLeastOS10_10()); - EXPECT_FALSE(IsOS10_11()); - EXPECT_FALSE(IsAtMostOS10_11()); - EXPECT_TRUE(IsAtLeastOS10_11()); - EXPECT_TRUE(IsOS10_12()); - EXPECT_TRUE(IsAtMostOS10_12()); - EXPECT_TRUE(IsAtLeastOS10_12()); - EXPECT_FALSE(IsOS10_13()); - EXPECT_FALSE(IsAtLeastOS10_13()); - EXPECT_TRUE(IsAtMostOS10_13()); - EXPECT_FALSE(IsOSLaterThan10_13_DontCallThis()); - } else if (minor == 13) { - EXPECT_FALSE(IsOS10_9()); - EXPECT_FALSE(IsAtMostOS10_9()); - EXPECT_TRUE(IsAtLeastOS10_9()); - EXPECT_FALSE(IsOS10_10()); - EXPECT_FALSE(IsAtMostOS10_10()); - EXPECT_TRUE(IsAtLeastOS10_10()); - EXPECT_FALSE(IsOS10_11()); - EXPECT_FALSE(IsAtMostOS10_11()); - EXPECT_TRUE(IsAtLeastOS10_11()); - EXPECT_FALSE(IsOS10_12()); - EXPECT_FALSE(IsAtMostOS10_12()); - EXPECT_TRUE(IsAtLeastOS10_12()); - EXPECT_TRUE(IsOS10_13()); - EXPECT_TRUE(IsAtLeastOS10_13()); - EXPECT_TRUE(IsAtMostOS10_13()); - EXPECT_FALSE(IsOSLaterThan10_13_DontCallThis()); - } else { - // Not nine, ten, eleven, twelve, or thirteen. Ah, ah, ah. - EXPECT_TRUE(false); - } - } else { - // Not ten. What you gonna do? - EXPECT_FALSE(true); - } -} - -TEST_F(MacUtilTest, ParseModelIdentifier) { - std::string model; - int32_t major = 1, minor = 2; - - EXPECT_FALSE(ParseModelIdentifier("", &model, &major, &minor)); - EXPECT_EQ(0U, model.length()); - EXPECT_EQ(1, major); - EXPECT_EQ(2, minor); - EXPECT_FALSE(ParseModelIdentifier("FooBar", &model, &major, &minor)); - - EXPECT_TRUE(ParseModelIdentifier("MacPro4,1", &model, &major, &minor)); - EXPECT_EQ(model, "MacPro"); - EXPECT_EQ(4, major); - EXPECT_EQ(1, minor); - - EXPECT_TRUE(ParseModelIdentifier("MacBookPro6,2", &model, &major, &minor)); - EXPECT_EQ(model, "MacBookPro"); - EXPECT_EQ(6, major); - EXPECT_EQ(2, minor); -} - -TEST_F(MacUtilTest, TestRemoveQuarantineAttribute) { - ScopedTempDir temp_dir_; - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - FilePath dummy_folder_path = temp_dir_.GetPath().Append("DummyFolder"); - ASSERT_TRUE(base::CreateDirectory(dummy_folder_path)); - const char* quarantine_str = "0000;4b392bb2;Chromium;|org.chromium.Chromium"; - const char* file_path_str = dummy_folder_path.value().c_str(); - EXPECT_EQ(0, setxattr(file_path_str, "com.apple.quarantine", - quarantine_str, strlen(quarantine_str), 0, 0)); - EXPECT_EQ(static_cast<long>(strlen(quarantine_str)), - getxattr(file_path_str, "com.apple.quarantine", - NULL, 0, 0, 0)); - EXPECT_TRUE(RemoveQuarantineAttribute(dummy_folder_path)); - EXPECT_EQ(-1, getxattr(file_path_str, "com.apple.quarantine", NULL, 0, 0, 0)); - EXPECT_EQ(ENOATTR, errno); -} - -TEST_F(MacUtilTest, TestRemoveQuarantineAttributeTwice) { - ScopedTempDir temp_dir_; - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - FilePath dummy_folder_path = temp_dir_.GetPath().Append("DummyFolder"); - const char* file_path_str = dummy_folder_path.value().c_str(); - ASSERT_TRUE(base::CreateDirectory(dummy_folder_path)); - EXPECT_EQ(-1, getxattr(file_path_str, "com.apple.quarantine", NULL, 0, 0, 0)); - // No quarantine attribute to begin with, but RemoveQuarantineAttribute still - // succeeds because in the end the folder still doesn't have the quarantine - // attribute set. - EXPECT_TRUE(RemoveQuarantineAttribute(dummy_folder_path)); - EXPECT_TRUE(RemoveQuarantineAttribute(dummy_folder_path)); - EXPECT_EQ(ENOATTR, errno); -} - -TEST_F(MacUtilTest, TestRemoveQuarantineAttributeNonExistentPath) { - ScopedTempDir temp_dir_; - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - FilePath non_existent_path = temp_dir_.GetPath().Append("DummyPath"); - ASSERT_FALSE(PathExists(non_existent_path)); - EXPECT_FALSE(RemoveQuarantineAttribute(non_existent_path)); -} - -} // namespace - -} // namespace mac -} // namespace base
diff --git a/base/mac/objc_release_properties_unittest.mm b/base/mac/objc_release_properties_unittest.mm deleted file mode 100644 index 2d90127..0000000 --- a/base/mac/objc_release_properties_unittest.mm +++ /dev/null
@@ -1,375 +0,0 @@ -// Copyright 2016 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 "base/mac/objc_release_properties.h" -#include "base/stl_util.h" - -#import "base/mac/scoped_nsautorelease_pool.h" -#include "testing/gtest/include/gtest/gtest.h" - -#import <objc/runtime.h> - -// "When I'm alone, I count myself." -// --Count von Count, http://www.youtube.com/watch?v=FKzszqa9WA4 - -namespace { - -// The number of CountVonCounts outstanding. -int ah_ah_ah; - -// NumberHolder exists to exercise the property attribute string parser by -// providing a named struct and an anonymous union. -struct NumberHolder { - union { - long long sixty_four; - int thirty_two; - short sixteen; - char eight; - } what; - enum { SIXTY_FOUR, THIRTY_TWO, SIXTEEN, EIGHT } how; -}; - -} // namespace - -@interface CountVonCount : NSObject<NSCopying> - -+ (CountVonCount*)countVonCount; - -@end // @interface CountVonCount - -@implementation CountVonCount - -+ (CountVonCount*)countVonCount { - return [[[CountVonCount alloc] init] autorelease]; -} - -- (id)init { - ++ah_ah_ah; - return [super init]; -} - -- (void)dealloc { - --ah_ah_ah; - [super dealloc]; -} - -- (id)copyWithZone:(NSZone*)zone { - return [[CountVonCount allocWithZone:zone] init]; -} - -@end // @implementation CountVonCount - -@interface ObjCPropertyTestBase : NSObject { - @private - CountVonCount* baseCvcRetain_; - CountVonCount* baseCvcCopy_; - CountVonCount* baseCvcAssign_; - CountVonCount* baseCvcNotProperty_; - CountVonCount* baseCvcNil_; - CountVonCount* baseCvcCustom_; - int baseInt_; - double baseDouble_; - void* basePointer_; - NumberHolder baseStruct_; -} - -@property(retain, nonatomic) CountVonCount* baseCvcRetain; -@property(copy, nonatomic) CountVonCount* baseCvcCopy; -@property(assign, nonatomic) CountVonCount* baseCvcAssign; -@property(retain, nonatomic) CountVonCount* baseCvcNil; -@property(retain, nonatomic, getter=baseCustom, setter=setBaseCustom:) - CountVonCount* baseCvcCustom; -@property(readonly, retain, nonatomic) CountVonCount* baseCvcReadOnly; -@property(retain, nonatomic) CountVonCount* baseCvcDynamic; -@property(assign, nonatomic) int baseInt; -@property(assign, nonatomic) double baseDouble; -@property(assign, nonatomic) void* basePointer; -@property(assign, nonatomic) NumberHolder baseStruct; - -- (void)setBaseCvcNotProperty:(CountVonCount*)cvc; - -@end // @interface ObjCPropertyTestBase - -@implementation ObjCPropertyTestBase - -@synthesize baseCvcRetain = baseCvcRetain_; -@synthesize baseCvcCopy = baseCvcCopy_; -@synthesize baseCvcAssign = baseCvcAssign_; -@synthesize baseCvcNil = baseCvcNil_; -@synthesize baseCvcCustom = baseCvcCustom_; -@synthesize baseCvcReadOnly = baseCvcReadOnly_; -@dynamic baseCvcDynamic; -@synthesize baseInt = baseInt_; -@synthesize baseDouble = baseDouble_; -@synthesize basePointer = basePointer_; -@synthesize baseStruct = baseStruct_; - -- (void)dealloc { - [baseCvcNotProperty_ release]; - base::mac::ReleaseProperties(self); - [super dealloc]; -} - -- (void)setBaseCvcNotProperty:(CountVonCount*)cvc { - if (cvc != baseCvcNotProperty_) { - [baseCvcNotProperty_ release]; - baseCvcNotProperty_ = [cvc retain]; - } -} - -- (void)setBaseCvcReadOnlyProperty:(CountVonCount*)cvc { - if (cvc != baseCvcReadOnly_) { - [baseCvcReadOnly_ release]; - baseCvcReadOnly_ = [cvc retain]; - } -} - -@end // @implementation ObjCPropertyTestBase - -@protocol ObjCPropertyTestProtocol - -@property(retain, nonatomic) CountVonCount* protoCvcRetain; -@property(copy, nonatomic) CountVonCount* protoCvcCopy; -@property(assign, nonatomic) CountVonCount* protoCvcAssign; -@property(retain, nonatomic) CountVonCount* protoCvcNil; -@property(retain, nonatomic, getter=protoCustom, setter=setProtoCustom:) - CountVonCount* protoCvcCustom; -@property(retain, nonatomic) CountVonCount* protoCvcDynamic; -@property(assign, nonatomic) int protoInt; -@property(assign, nonatomic) double protoDouble; -@property(assign, nonatomic) void* protoPointer; -@property(assign, nonatomic) NumberHolder protoStruct; - -@end // @protocol ObjCPropertyTestProtocol - -// @protocol(NSObject) declares some (copy, readonly) properties (superclass, -// description, debugDescription, and hash), but we're not expected to release -// them. The current implementation only releases properties backed by instance -// variables, and this makes sure that doesn't change in a breaking way. -@interface ObjCPropertyTestDerived - : ObjCPropertyTestBase<ObjCPropertyTestProtocol, NSObject> { - @private - CountVonCount* derivedCvcRetain_; - CountVonCount* derivedCvcCopy_; - CountVonCount* derivedCvcAssign_; - CountVonCount* derivedCvcNotProperty_; - CountVonCount* derivedCvcNil_; - CountVonCount* derivedCvcCustom_; - int derivedInt_; - double derivedDouble_; - void* derivedPointer_; - NumberHolder derivedStruct_; - - CountVonCount* protoCvcRetain_; - CountVonCount* protoCvcCopy_; - CountVonCount* protoCvcAssign_; - CountVonCount* protoCvcNil_; - CountVonCount* protoCvcCustom_; - int protoInt_; - double protoDouble_; - void* protoPointer_; - NumberHolder protoStruct_; -} - -@property(retain, nonatomic) CountVonCount* derivedCvcRetain; -@property(copy, nonatomic) CountVonCount* derivedCvcCopy; -@property(assign, nonatomic) CountVonCount* derivedCvcAssign; -@property(retain, nonatomic) CountVonCount* derivedCvcNil; -@property(retain, nonatomic, getter=derivedCustom, setter=setDerivedCustom:) - CountVonCount* derivedCvcCustom; -@property(retain, nonatomic) CountVonCount* derivedCvcDynamic; -@property(assign, nonatomic) int derivedInt; -@property(assign, nonatomic) double derivedDouble; -@property(assign, nonatomic) void* derivedPointer; -@property(assign, nonatomic) NumberHolder derivedStruct; - -- (void)setDerivedCvcNotProperty:(CountVonCount*)cvc; - -@end // @interface ObjCPropertyTestDerived - -@implementation ObjCPropertyTestDerived - -@synthesize derivedCvcRetain = derivedCvcRetain_; -@synthesize derivedCvcCopy = derivedCvcCopy_; -@synthesize derivedCvcAssign = derivedCvcAssign_; -@synthesize derivedCvcNil = derivedCvcNil_; -@synthesize derivedCvcCustom = derivedCvcCustom_; -@dynamic derivedCvcDynamic; -@synthesize derivedInt = derivedInt_; -@synthesize derivedDouble = derivedDouble_; -@synthesize derivedPointer = derivedPointer_; -@synthesize derivedStruct = derivedStruct_; - -@synthesize protoCvcRetain = protoCvcRetain_; -@synthesize protoCvcCopy = protoCvcCopy_; -@synthesize protoCvcAssign = protoCvcAssign_; -@synthesize protoCvcNil = protoCvcNil_; -@synthesize protoCvcCustom = protoCvcCustom_; -@dynamic protoCvcDynamic; -@synthesize protoInt = protoInt_; -@synthesize protoDouble = protoDouble_; -@synthesize protoPointer = protoPointer_; -@synthesize protoStruct = protoStruct_; - -+ (BOOL)resolveInstanceMethod:(SEL)sel { - static const std::vector<SEL> dynamicMethods { - @selector(baseCvcDynamic), @selector(derivedCvcDynamic), - @selector(protoCvcDynamic), - }; - if (!base::ContainsValue(dynamicMethods, sel)) { - return NO; - } - id (*imp)() = []() -> id { return nil; }; - class_addMethod([self class], sel, reinterpret_cast<IMP>(imp), "@@:"); - return YES; -} - -- (void)dealloc { - base::mac::ReleaseProperties(self); - [derivedCvcNotProperty_ release]; - [super dealloc]; -} - -- (void)setDerivedCvcNotProperty:(CountVonCount*)cvc { - if (cvc != derivedCvcNotProperty_) { - [derivedCvcNotProperty_ release]; - derivedCvcNotProperty_ = [cvc retain]; - } -} - -@end // @implementation ObjCPropertyTestDerived - -@interface ObjcPropertyTestEmpty : NSObject -@end - -@implementation ObjcPropertyTestEmpty - -- (void)dealloc { - base::mac::ReleaseProperties(self); - [super dealloc]; -} - -@end // @implementation ObjcPropertyTestEmpty - -namespace { - -TEST(ObjCReleasePropertiesTest, SesameStreet) { - ObjCPropertyTestDerived* test_object = [[ObjCPropertyTestDerived alloc] init]; - - // Assure a clean slate. - EXPECT_EQ(0, ah_ah_ah); - EXPECT_EQ(1U, [test_object retainCount]); - - CountVonCount* baseAssign = [[CountVonCount alloc] init]; - CountVonCount* derivedAssign = [[CountVonCount alloc] init]; - CountVonCount* protoAssign = [[CountVonCount alloc] init]; - - // Make sure that worked before things get more involved. - EXPECT_EQ(3, ah_ah_ah); - - { - base::mac::ScopedNSAutoreleasePool pool; - - test_object.baseCvcRetain = [CountVonCount countVonCount]; - test_object.baseCvcCopy = [CountVonCount countVonCount]; - test_object.baseCvcAssign = baseAssign; - test_object.baseCvcCustom = [CountVonCount countVonCount]; - [test_object setBaseCvcReadOnlyProperty:[CountVonCount countVonCount]]; - [test_object setBaseCvcNotProperty:[CountVonCount countVonCount]]; - - // That added 5 objects, plus 1 more that was copied. - EXPECT_EQ(9, ah_ah_ah); - - test_object.derivedCvcRetain = [CountVonCount countVonCount]; - test_object.derivedCvcCopy = [CountVonCount countVonCount]; - test_object.derivedCvcAssign = derivedAssign; - test_object.derivedCvcCustom = [CountVonCount countVonCount]; - [test_object setDerivedCvcNotProperty:[CountVonCount countVonCount]]; - - // That added 4 objects, plus 1 more that was copied. - EXPECT_EQ(14, ah_ah_ah); - - test_object.protoCvcRetain = [CountVonCount countVonCount]; - test_object.protoCvcCopy = [CountVonCount countVonCount]; - test_object.protoCvcAssign = protoAssign; - test_object.protoCvcCustom = [CountVonCount countVonCount]; - - // That added 3 objects, plus 1 more that was copied. - EXPECT_EQ(18, ah_ah_ah); - } - - // Now that the autorelease pool has been popped, the 3 objects that were - // copied when placed into the test object will have been deallocated. - EXPECT_EQ(15, ah_ah_ah); - - // Make sure that the setters wo/rk and have the expected semantics. - test_object.baseCvcRetain = nil; - test_object.baseCvcCopy = nil; - test_object.baseCvcAssign = nil; - test_object.baseCvcCustom = nil; - test_object.derivedCvcRetain = nil; - test_object.derivedCvcCopy = nil; - test_object.derivedCvcAssign = nil; - test_object.derivedCvcCustom = nil; - test_object.protoCvcRetain = nil; - test_object.protoCvcCopy = nil; - test_object.protoCvcAssign = nil; - test_object.protoCvcCustom = nil; - - // The CountVonCounts marked "retain" and "copy" should have been - // deallocated. Those marked assign should not have been. The only ones that - // should exist now are the ones marked "assign", the ones held in - // non-property instance variables, and the ones held in properties marked - // readonly. - EXPECT_EQ(6, ah_ah_ah); - - { - base::mac::ScopedNSAutoreleasePool pool; - - // Put things back to how they were. - test_object.baseCvcRetain = [CountVonCount countVonCount]; - test_object.baseCvcCopy = [CountVonCount countVonCount]; - test_object.baseCvcAssign = baseAssign; - test_object.baseCvcCustom = [CountVonCount countVonCount]; - test_object.derivedCvcRetain = [CountVonCount countVonCount]; - test_object.derivedCvcCopy = [CountVonCount countVonCount]; - test_object.derivedCvcAssign = derivedAssign; - test_object.derivedCvcCustom = [CountVonCount countVonCount]; - test_object.protoCvcRetain = [CountVonCount countVonCount]; - test_object.protoCvcCopy = [CountVonCount countVonCount]; - test_object.protoCvcAssign = protoAssign; - test_object.protoCvcCustom = [CountVonCount countVonCount]; - - // 9 more CountVonCounts, 3 of which were copied. - EXPECT_EQ(18, ah_ah_ah); - } - - // Now that the autorelease pool has been popped, the 3 copies are gone. - EXPECT_EQ(15, ah_ah_ah); - - // Releasing the test object should get rid of everything that it owns. - [test_object release]; - - // base::mac::ReleaseProperties(self) should have released all of the - // CountVonCounts associated with properties marked "retain" or "copy". The - // -dealloc methods in each should have released the single non-property - // objects in each. Only the CountVonCounts assigned to the properties marked - // "assign" should remain. - EXPECT_EQ(3, ah_ah_ah); - - [baseAssign release]; - [derivedAssign release]; - [protoAssign release]; - - // Zero! Zero counts! Ah, ah, ah. - EXPECT_EQ(0, ah_ah_ah); -} - -TEST(ObjCReleasePropertiesTest, EmptyObject) { - // Test that ReleaseProperties doesn't do anything unexpected to a class - // with no properties. - [[[ObjcPropertyTestEmpty alloc] init] release]; -} - -} // namespace
diff --git a/base/mac/scoped_nsobject_unittest.mm b/base/mac/scoped_nsobject_unittest.mm deleted file mode 100644 index 72d5242..0000000 --- a/base/mac/scoped_nsobject_unittest.mm +++ /dev/null
@@ -1,102 +0,0 @@ -// Copyright (c) 2012 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 <vector> - -#include "base/mac/scoped_nsautorelease_pool.h" -#include "base/mac/scoped_nsobject.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -TEST(ScopedNSObjectTest, ScopedNSObject) { - base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]); - ASSERT_TRUE(p1.get()); - ASSERT_EQ(1u, [p1 retainCount]); - base::scoped_nsobject<NSObject> p2(p1); - ASSERT_EQ(p1.get(), p2.get()); - ASSERT_EQ(2u, [p1 retainCount]); - p2.reset(); - ASSERT_EQ(nil, p2.get()); - ASSERT_EQ(1u, [p1 retainCount]); - { - base::scoped_nsobject<NSObject> p3 = p1; - ASSERT_EQ(p1.get(), p3.get()); - ASSERT_EQ(2u, [p1 retainCount]); - { - base::mac::ScopedNSAutoreleasePool pool; - p3 = p1; - } - ASSERT_EQ(p1.get(), p3.get()); - ASSERT_EQ(2u, [p1 retainCount]); - } - ASSERT_EQ(1u, [p1 retainCount]); - base::scoped_nsobject<NSObject> p4([p1.get() retain]); - ASSERT_EQ(2u, [p1 retainCount]); - ASSERT_TRUE(p1 == p1.get()); - ASSERT_TRUE(p1 == p1); - ASSERT_FALSE(p1 != p1); - ASSERT_FALSE(p1 != p1.get()); - base::scoped_nsobject<NSObject> p5([[NSObject alloc] init]); - ASSERT_TRUE(p1 != p5); - ASSERT_TRUE(p1 != p5.get()); - ASSERT_FALSE(p1 == p5); - ASSERT_FALSE(p1 == p5.get()); - - base::scoped_nsobject<NSObject> p6 = p1; - ASSERT_EQ(3u, [p6 retainCount]); - { - base::mac::ScopedNSAutoreleasePool pool; - p6.autorelease(); - ASSERT_EQ(nil, p6.get()); - ASSERT_EQ(3u, [p1 retainCount]); - } - ASSERT_EQ(2u, [p1 retainCount]); - - base::scoped_nsobject<NSObject> p7([NSObject new]); - base::scoped_nsobject<NSObject> p8(std::move(p7)); - ASSERT_TRUE(p8); - ASSERT_EQ(1u, [p8 retainCount]); - ASSERT_FALSE(p7.get()); -} - -// Instantiating scoped_nsobject<> with T=NSAutoreleasePool should trip a -// static_assert. -#if 0 -TEST(ScopedNSObjectTest, FailToCreateScopedNSObjectAutoreleasePool) { - base::scoped_nsobject<NSAutoreleasePool> pool; -} -#endif - -TEST(ScopedNSObjectTest, ScopedNSObjectInContainer) { - base::scoped_nsobject<id> p([[NSObject alloc] init]); - ASSERT_TRUE(p.get()); - ASSERT_EQ(1u, [p retainCount]); - { - std::vector<base::scoped_nsobject<id>> objects; - objects.push_back(p); - ASSERT_EQ(2u, [p retainCount]); - ASSERT_EQ(p.get(), objects[0].get()); - objects.push_back(base::scoped_nsobject<id>([[NSObject alloc] init])); - ASSERT_TRUE(objects[1].get()); - ASSERT_EQ(1u, [objects[1] retainCount]); - } - ASSERT_EQ(1u, [p retainCount]); -} - -TEST(ScopedNSObjectTest, ScopedNSObjectFreeFunctions) { - base::scoped_nsobject<id> p1([[NSObject alloc] init]); - id o1 = p1.get(); - ASSERT_TRUE(o1 == p1); - ASSERT_FALSE(o1 != p1); - base::scoped_nsobject<id> p2([[NSObject alloc] init]); - ASSERT_TRUE(o1 != p2); - ASSERT_FALSE(o1 == p2); - id o2 = p2.get(); - swap(p1, p2); - ASSERT_EQ(o2, p1.get()); - ASSERT_EQ(o1, p2.get()); -} - -} // namespace
diff --git a/base/mac/scoped_nsobject_unittest_arc.mm b/base/mac/scoped_nsobject_unittest_arc.mm deleted file mode 100644 index 5cbf3f8..0000000 --- a/base/mac/scoped_nsobject_unittest_arc.mm +++ /dev/null
@@ -1,131 +0,0 @@ -// Copyright (c) 2012 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 <vector> - -#import <CoreFoundation/CoreFoundation.h> - -#include "base/logging.h" -#import "base/mac/scoped_nsobject.h" -#include "testing/gtest/include/gtest/gtest.h" - -#if !defined(__has_feature) || !__has_feature(objc_arc) -#error "This file requires ARC support." -#endif - -namespace { - -template <typename NST> -CFIndex GetRetainCount(const base::scoped_nsobject<NST>& nst) { - @autoreleasepool { - return CFGetRetainCount((__bridge CFTypeRef)nst.get()) - 1; - } -} - -#if __has_feature(objc_arc_weak) -TEST(ScopedNSObjectTestARC, DefaultPolicyIsRetain) { - __weak id o; - @autoreleasepool { - base::scoped_nsprotocol<id> p([[NSObject alloc] init]); - o = p.get(); - DCHECK_EQ(o, p.get()); - } - DCHECK_EQ(o, nil); -} -#endif - -TEST(ScopedNSObjectTestARC, ScopedNSObject) { - base::scoped_nsobject<NSObject> p1([[NSObject alloc] init]); - @autoreleasepool { - EXPECT_TRUE(p1.get()); - EXPECT_TRUE(p1.get()); - } - EXPECT_EQ(1, GetRetainCount(p1)); - EXPECT_EQ(1, GetRetainCount(p1)); - base::scoped_nsobject<NSObject> p2(p1); - @autoreleasepool { - EXPECT_EQ(p1.get(), p2.get()); - } - EXPECT_EQ(2, GetRetainCount(p1)); - p2.reset(); - EXPECT_EQ(nil, p2.get()); - EXPECT_EQ(1, GetRetainCount(p1)); - { - base::scoped_nsobject<NSObject> p3 = p1; - @autoreleasepool { - EXPECT_EQ(p1.get(), p3.get()); - } - EXPECT_EQ(2, GetRetainCount(p1)); - @autoreleasepool { - p3 = p1; - EXPECT_EQ(p1.get(), p3.get()); - } - EXPECT_EQ(2, GetRetainCount(p1)); - } - EXPECT_EQ(1, GetRetainCount(p1)); - base::scoped_nsobject<NSObject> p4; - @autoreleasepool { - p4 = base::scoped_nsobject<NSObject>(p1.get()); - } - EXPECT_EQ(2, GetRetainCount(p1)); - @autoreleasepool { - EXPECT_TRUE(p1 == p1.get()); - EXPECT_TRUE(p1 == p1); - EXPECT_FALSE(p1 != p1); - EXPECT_FALSE(p1 != p1.get()); - } - base::scoped_nsobject<NSObject> p5([[NSObject alloc] init]); - @autoreleasepool { - EXPECT_TRUE(p1 != p5); - EXPECT_TRUE(p1 != p5.get()); - EXPECT_FALSE(p1 == p5); - EXPECT_FALSE(p1 == p5.get()); - } - - base::scoped_nsobject<NSObject> p6 = p1; - EXPECT_EQ(3, GetRetainCount(p6)); - @autoreleasepool { - p6.autorelease(); - EXPECT_EQ(nil, p6.get()); - } - EXPECT_EQ(2, GetRetainCount(p1)); -} - -TEST(ScopedNSObjectTestARC, ScopedNSObjectInContainer) { - base::scoped_nsobject<id> p([[NSObject alloc] init]); - @autoreleasepool { - EXPECT_TRUE(p.get()); - } - EXPECT_EQ(1, GetRetainCount(p)); - @autoreleasepool { - std::vector<base::scoped_nsobject<id>> objects; - objects.push_back(p); - EXPECT_EQ(2, GetRetainCount(p)); - @autoreleasepool { - EXPECT_EQ(p.get(), objects[0].get()); - } - objects.push_back(base::scoped_nsobject<id>([[NSObject alloc] init])); - @autoreleasepool { - EXPECT_TRUE(objects[1].get()); - } - EXPECT_EQ(1, GetRetainCount(objects[1])); - } - EXPECT_EQ(1, GetRetainCount(p)); -} - -TEST(ScopedNSObjectTestARC, ScopedNSObjectFreeFunctions) { - base::scoped_nsobject<id> p1([[NSObject alloc] init]); - id o1 = p1.get(); - EXPECT_TRUE(o1 == p1); - EXPECT_FALSE(o1 != p1); - base::scoped_nsobject<id> p2([[NSObject alloc] init]); - EXPECT_TRUE(o1 != p2); - EXPECT_FALSE(o1 == p2); - id o2 = p2.get(); - swap(p1, p2); - EXPECT_EQ(o2, p1.get()); - EXPECT_EQ(o1, p2.get()); -} - -} // namespace
diff --git a/base/mac/scoped_objc_class_swizzler_unittest.mm b/base/mac/scoped_objc_class_swizzler_unittest.mm deleted file mode 100644 index 79820a3..0000000 --- a/base/mac/scoped_objc_class_swizzler_unittest.mm +++ /dev/null
@@ -1,167 +0,0 @@ -// Copyright 2014 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. - -#import "base/mac/scoped_objc_class_swizzler.h" - -#import "base/mac/scoped_nsobject.h" -#include "testing/gtest/include/gtest/gtest.h" - -@interface ObjCClassSwizzlerTestOne : NSObject -+ (NSInteger)function; -- (NSInteger)method; -- (NSInteger)modifier; -@end - -@interface ObjCClassSwizzlerTestTwo : NSObject -+ (NSInteger)function; -- (NSInteger)method; -- (NSInteger)modifier; -@end - -@implementation ObjCClassSwizzlerTestOne : NSObject - -+ (NSInteger)function { - return 10; -} - -- (NSInteger)method { - // Multiply by a modifier to ensure |self| in a swizzled implementation - // refers to the original object. - return 1 * [self modifier]; -} - -- (NSInteger)modifier { - return 3; -} - -@end - -@implementation ObjCClassSwizzlerTestTwo : NSObject - -+ (NSInteger)function { - return 20; -} - -- (NSInteger)method { - return 2 * [self modifier]; -} - -- (NSInteger)modifier { - return 7; -} - -@end - -@interface ObjCClassSwizzlerTestOne (AlternateCategory) -- (NSInteger)alternate; -@end - -@implementation ObjCClassSwizzlerTestOne (AlternateCategory) -- (NSInteger)alternate { - return 3 * [self modifier]; -} -@end - -@interface ObjCClassSwizzlerTestOneChild : ObjCClassSwizzlerTestOne -- (NSInteger)childAlternate; -@end - -@implementation ObjCClassSwizzlerTestOneChild -- (NSInteger)childAlternate { - return 5 * [self modifier]; -} -@end - -namespace base { -namespace mac { - -TEST(ObjCClassSwizzlerTest, SwizzleInstanceMethods) { - base::scoped_nsobject<ObjCClassSwizzlerTestOne> object_one( - [[ObjCClassSwizzlerTestOne alloc] init]); - base::scoped_nsobject<ObjCClassSwizzlerTestTwo> object_two( - [[ObjCClassSwizzlerTestTwo alloc] init]); - EXPECT_EQ(3, [object_one method]); - EXPECT_EQ(14, [object_two method]); - - { - base::mac::ScopedObjCClassSwizzler swizzler( - [ObjCClassSwizzlerTestOne class], - [ObjCClassSwizzlerTestTwo class], - @selector(method)); - EXPECT_EQ(6, [object_one method]); - EXPECT_EQ(7, [object_two method]); - - IMP original = swizzler.GetOriginalImplementation(); - id expected_result = reinterpret_cast<id>(3); - EXPECT_EQ(expected_result, original(object_one, @selector(method))); - } - - EXPECT_EQ(3, [object_one method]); - EXPECT_EQ(14, [object_two method]); -} - -TEST(ObjCClassSwizzlerTest, SwizzleClassMethods) { - EXPECT_EQ(10, [ObjCClassSwizzlerTestOne function]); - EXPECT_EQ(20, [ObjCClassSwizzlerTestTwo function]); - - { - base::mac::ScopedObjCClassSwizzler swizzler( - [ObjCClassSwizzlerTestOne class], - [ObjCClassSwizzlerTestTwo class], - @selector(function)); - EXPECT_EQ(20, [ObjCClassSwizzlerTestOne function]); - EXPECT_EQ(10, [ObjCClassSwizzlerTestTwo function]); - - IMP original = swizzler.GetOriginalImplementation(); - id expected_result = reinterpret_cast<id>(10); - EXPECT_EQ(expected_result, - original([ObjCClassSwizzlerTestOne class], @selector(function))); - } - - EXPECT_EQ(10, [ObjCClassSwizzlerTestOne function]); - EXPECT_EQ(20, [ObjCClassSwizzlerTestTwo function]); -} - -TEST(ObjCClassSwizzlerTest, SwizzleViaCategory) { - base::scoped_nsobject<ObjCClassSwizzlerTestOne> object_one( - [[ObjCClassSwizzlerTestOne alloc] init]); - EXPECT_EQ(3, [object_one method]); - - { - base::mac::ScopedObjCClassSwizzler swizzler( - [ObjCClassSwizzlerTestOne class], - @selector(method), - @selector(alternate)); - EXPECT_EQ(9, [object_one method]); - - IMP original = swizzler.GetOriginalImplementation(); - id expected_result = reinterpret_cast<id>(3); - EXPECT_EQ(expected_result, original(object_one, @selector(method))); - } - - EXPECT_EQ(3, [object_one method]); -} - -TEST(ObjCClassSwizzlerTest, SwizzleViaInheritance) { - base::scoped_nsobject<ObjCClassSwizzlerTestOneChild> child( - [[ObjCClassSwizzlerTestOneChild alloc] init]); - EXPECT_EQ(3, [child method]); - - { - base::mac::ScopedObjCClassSwizzler swizzler( - [ObjCClassSwizzlerTestOneChild class], - @selector(method), - @selector(childAlternate)); - EXPECT_EQ(15, [child method]); - - IMP original = swizzler.GetOriginalImplementation(); - id expected_result = reinterpret_cast<id>(3); - EXPECT_EQ(expected_result, original(child, @selector(method))); - } - - EXPECT_EQ(3, [child method]); -} - -} // namespace mac -} // namespace base
diff --git a/base/mac/scoped_sending_event_unittest.mm b/base/mac/scoped_sending_event_unittest.mm deleted file mode 100644 index 52f18c6..0000000 --- a/base/mac/scoped_sending_event_unittest.mm +++ /dev/null
@@ -1,63 +0,0 @@ -// 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. - -#import "base/mac/scoped_sending_event.h" - -#import <Foundation/Foundation.h> - -#include "base/mac/scoped_nsobject.h" -#include "testing/gtest/include/gtest/gtest.h" - -@interface ScopedSendingEventTestCrApp : NSApplication <CrAppControlProtocol> { - @private - BOOL handlingSendEvent_; -} -@property(nonatomic, assign, getter=isHandlingSendEvent) BOOL handlingSendEvent; -@end - -@implementation ScopedSendingEventTestCrApp -@synthesize handlingSendEvent = handlingSendEvent_; -@end - -namespace { - -class ScopedSendingEventTest : public testing::Test { - public: - ScopedSendingEventTest() : app_([[ScopedSendingEventTestCrApp alloc] init]) { - NSApp = app_.get(); - } - ~ScopedSendingEventTest() override { NSApp = nil; } - - private: - base::scoped_nsobject<ScopedSendingEventTestCrApp> app_; -}; - -// Sets the flag within scope, resets when leaving scope. -TEST_F(ScopedSendingEventTest, SetHandlingSendEvent) { - id<CrAppProtocol> app = NSApp; - EXPECT_FALSE([app isHandlingSendEvent]); - { - base::mac::ScopedSendingEvent is_handling_send_event; - EXPECT_TRUE([app isHandlingSendEvent]); - } - EXPECT_FALSE([app isHandlingSendEvent]); -} - -// Nested call restores previous value rather than resetting flag. -TEST_F(ScopedSendingEventTest, NestedSetHandlingSendEvent) { - id<CrAppProtocol> app = NSApp; - EXPECT_FALSE([app isHandlingSendEvent]); - { - base::mac::ScopedSendingEvent is_handling_send_event; - EXPECT_TRUE([app isHandlingSendEvent]); - { - base::mac::ScopedSendingEvent nested_is_handling_send_event; - EXPECT_TRUE([app isHandlingSendEvent]); - } - EXPECT_TRUE([app isHandlingSendEvent]); - } - EXPECT_FALSE([app isHandlingSendEvent]); -} - -} // namespace
diff --git a/base/process/launch.cc b/base/process/launch.cc deleted file mode 100644 index dbb8447..0000000 --- a/base/process/launch.cc +++ /dev/null
@@ -1,27 +0,0 @@ -// Copyright (c) 2013 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 "base/process/launch.h" -#include "build_config.h" - -namespace base { - -LaunchOptions::LaunchOptions() = default; - -LaunchOptions::LaunchOptions(const LaunchOptions& other) = default; - -LaunchOptions::~LaunchOptions() = default; - -LaunchOptions LaunchOptionsForTest() { - LaunchOptions options; -#if defined(OS_LINUX) - // To prevent accidental privilege sharing to an untrusted child, processes - // are started with PR_SET_NO_NEW_PRIVS. Do not set that here, since this - // new child will be used for testing only. - options.allow_new_privs = true; -#endif - return options; -} - -} // namespace base
diff --git a/base/process/launch.h b/base/process/launch.h deleted file mode 100644 index eb53c0f..0000000 --- a/base/process/launch.h +++ /dev/null
@@ -1,345 +0,0 @@ -// Copyright 2013 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. - -// This file contains functions for launching subprocesses. - -#ifndef BASE_PROCESS_LAUNCH_H_ -#define BASE_PROCESS_LAUNCH_H_ - -#include <stddef.h> - -#include <string> -#include <utility> -#include <vector> - -#include "base/base_export.h" -#include "base/environment.h" -#include "base/macros.h" -#include "base/process/process.h" -#include "base/process/process_handle.h" -#include "base/strings/string_piece.h" -#include "build_config.h" - -#if defined(OS_WIN) -#include <windows.h> -#endif - -#if defined(OS_POSIX) -#include "base/posix/file_descriptor_shuffle.h" -#endif - -namespace base { - -class CommandLine; - -#if defined(OS_WIN) -typedef std::vector<HANDLE> HandlesToInheritVector; -#elif defined(OS_POSIX) -typedef std::vector<std::pair<int, int>> FileHandleMappingVector; -#endif // defined(OS_WIN) - -// Options for launching a subprocess that are passed to LaunchProcess(). -// The default constructor constructs the object with default options. -struct BASE_EXPORT LaunchOptions { -#if defined(OS_POSIX) - // Delegate to be run in between fork and exec in the subprocess (see - // pre_exec_delegate below) - class BASE_EXPORT PreExecDelegate { - public: - PreExecDelegate() = default; - virtual ~PreExecDelegate() = default; - - // Since this is to be run between fork and exec, and fork may have happened - // while multiple threads were running, this function needs to be async - // safe. - virtual void RunAsyncSafe() = 0; - - private: - DISALLOW_COPY_AND_ASSIGN(PreExecDelegate); - }; -#endif // defined(OS_POSIX) - - LaunchOptions(); - LaunchOptions(const LaunchOptions&); - ~LaunchOptions(); - - // If true, wait for the process to complete. - bool wait = false; - - // If not empty, change to this directory before executing the new process. - base::FilePath current_directory; - -#if defined(OS_WIN) - bool start_hidden = false; - - // Windows can inherit handles when it launches child processes. - // See https://blogs.msdn.microsoft.com/oldnewthing/20111216-00/?p=8873 - // for a good overview of Windows handle inheritance. - // - // Implementation note: it might be nice to implement in terms of - // base::Optional<>, but then the natural default state (vector not present) - // would be "all inheritable handles" while we want "no inheritance." - enum class Inherit { - // Only those handles in |handles_to_inherit| vector are inherited. If the - // vector is empty, no handles are inherited. The handles in the vector must - // all be inheritable. - kSpecific, - - // All handles in the current process which are inheritable are inherited. - // In production code this flag should be used only when running - // short-lived, trusted binaries, because open handles from other libraries - // and subsystems will leak to the child process, causing errors such as - // open socket hangs. There are also race conditions that can cause handle - // over-sharing. - // - // |handles_to_inherit| must be null. - // - // DEPRECATED. THIS SHOULD NOT BE USED. Explicitly map all handles that - // need to be shared in new code. - // TODO(brettw) bug 748258: remove this. - kAll - }; - Inherit inherit_mode = Inherit::kSpecific; - HandlesToInheritVector handles_to_inherit; - - // If non-null, runs as if the user represented by the token had launched it. - // Whether the application is visible on the interactive desktop depends on - // the token belonging to an interactive logon session. - // - // To avoid hard to diagnose problems, when specified this loads the - // environment variables associated with the user and if this operation fails - // the entire call fails as well. - UserTokenHandle as_user = nullptr; - - // If true, use an empty string for the desktop name. - bool empty_desktop_name = false; - - // If non-null, launches the application in that job object. The process will - // be terminated immediately and LaunchProcess() will fail if assignment to - // the job object fails. - HANDLE job_handle = nullptr; - - // Handles for the redirection of stdin, stdout and stderr. The caller should - // either set all three of them or none (i.e. there is no way to redirect - // stderr without redirecting stdin). - // - // The handles must be inheritable. Pseudo handles are used when stdout and - // stderr redirect to the console. In that case, GetFileType() will return - // FILE_TYPE_CHAR and they're automatically inherited by child processes. See - // https://msdn.microsoft.com/en-us/library/windows/desktop/ms682075.aspx - // Otherwise, the caller must ensure that the |inherit_mode| and/or - // |handles_to_inherit| set so that the handles are inherited. - HANDLE stdin_handle = nullptr; - HANDLE stdout_handle = nullptr; - HANDLE stderr_handle = nullptr; - - // If set to true, ensures that the child process is launched with the - // CREATE_BREAKAWAY_FROM_JOB flag which allows it to breakout of the parent - // job if any. - bool force_breakaway_from_job_ = false; - - // If set to true, permission to bring windows to the foreground is passed to - // the launched process if the current process has such permission. - bool grant_foreground_privilege = false; -#elif defined(OS_POSIX) - // Set/unset environment variables. These are applied on top of the parent - // process environment. Empty (the default) means to inherit the same - // environment. See AlterEnvironment(). - EnvironmentMap environ; - - // Clear the environment for the new process before processing changes from - // |environ|. - bool clear_environ = false; - - // Remap file descriptors according to the mapping of src_fd->dest_fd to - // propagate FDs into the child process. - FileHandleMappingVector fds_to_remap; -#endif // defined(OS_WIN) - -#if defined(OS_LINUX) - // If non-zero, start the process using clone(), using flags as provided. - // Unlike in clone, clone_flags may not contain a custom termination signal - // that is sent to the parent when the child dies. The termination signal will - // always be set to SIGCHLD. - int clone_flags = 0; - - // By default, child processes will have the PR_SET_NO_NEW_PRIVS bit set. If - // true, then this bit will not be set in the new child process. - bool allow_new_privs = false; - - // Sets parent process death signal to SIGKILL. - bool kill_on_parent_death = false; -#endif // defined(OS_LINUX) - -#if defined(OS_POSIX) - // If not empty, launch the specified executable instead of - // cmdline.GetProgram(). This is useful when it is necessary to pass a custom - // argv[0]. - base::FilePath real_path; - - // If non-null, a delegate to be run immediately prior to executing the new - // program in the child process. - // - // WARNING: If LaunchProcess is called in the presence of multiple threads, - // code running in this delegate essentially needs to be async-signal safe - // (see man 7 signal for a list of allowed functions). - PreExecDelegate* pre_exec_delegate = nullptr; - - // Each element is an RLIMIT_* constant that should be raised to its - // rlim_max. This pointer is owned by the caller and must live through - // the call to LaunchProcess(). - const std::vector<int>* maximize_rlimits = nullptr; - - // If true, start the process in a new process group, instead of - // inheriting the parent's process group. The pgid of the child process - // will be the same as its pid. - bool new_process_group = false; -#endif // defined(OS_POSIX) -}; - -// Launch a process via the command line |cmdline|. -// See the documentation of LaunchOptions for details on |options|. -// -// Returns a valid Process upon success. -// -// Unix-specific notes: -// - All file descriptors open in the parent process will be closed in the -// child process except for any preserved by options::fds_to_remap, and -// stdin, stdout, and stderr. If not remapped by options::fds_to_remap, -// stdin is reopened as /dev/null, and the child is allowed to inherit its -// parent's stdout and stderr. -// - If the first argument on the command line does not contain a slash, -// PATH will be searched. (See man execvp.) -BASE_EXPORT Process LaunchProcess(const CommandLine& cmdline, - const LaunchOptions& options); - -#if defined(OS_WIN) -// Windows-specific LaunchProcess that takes the command line as a -// string. Useful for situations where you need to control the -// command line arguments directly, but prefer the CommandLine version -// if launching Chrome itself. -// -// The first command line argument should be the path to the process, -// and don't forget to quote it. -// -// Example (including literal quotes) -// cmdline = "c:\windows\explorer.exe" -foo "c:\bar\" -BASE_EXPORT Process LaunchProcess(const string16& cmdline, - const LaunchOptions& options); - -// Launches a process with elevated privileges. This does not behave exactly -// like LaunchProcess as it uses ShellExecuteEx instead of CreateProcess to -// create the process. This means the process will have elevated privileges -// and thus some common operations like OpenProcess will fail. Currently the -// only supported LaunchOptions are |start_hidden| and |wait|. -BASE_EXPORT Process LaunchElevatedProcess(const CommandLine& cmdline, - const LaunchOptions& options); - -#elif defined(OS_POSIX) -// A POSIX-specific version of LaunchProcess that takes an argv array -// instead of a CommandLine. Useful for situations where you need to -// control the command line arguments directly, but prefer the -// CommandLine version if launching Chrome itself. -BASE_EXPORT Process LaunchProcess(const std::vector<std::string>& argv, - const LaunchOptions& options); - -// Close all file descriptors, except those which are a destination in the -// given multimap. Only call this function in a child process where you know -// that there aren't any other threads. -BASE_EXPORT void CloseSuperfluousFds(const InjectiveMultimap& saved_map); -#endif // defined(OS_WIN) - -#if defined(OS_WIN) -// Set |job_object|'s JOBOBJECT_EXTENDED_LIMIT_INFORMATION -// BasicLimitInformation.LimitFlags to |limit_flags|. -BASE_EXPORT bool SetJobObjectLimitFlags(HANDLE job_object, DWORD limit_flags); - -// Output multi-process printf, cout, cerr, etc to the cmd.exe console that ran -// chrome. This is not thread-safe: only call from main thread. -BASE_EXPORT void RouteStdioToConsole(bool create_console_if_not_found); -#endif // defined(OS_WIN) - -// Executes the application specified by |cl| and wait for it to exit. Stores -// the output (stdout) in |output|. Redirects stderr to /dev/null. Returns true -// on success (application launched and exited cleanly, with exit code -// indicating success). -BASE_EXPORT bool GetAppOutput(const CommandLine& cl, std::string* output); - -// Like GetAppOutput, but also includes stderr. -BASE_EXPORT bool GetAppOutputAndError(const CommandLine& cl, - std::string* output); - -// A version of |GetAppOutput()| which also returns the exit code of the -// executed command. Returns true if the application runs and exits cleanly. If -// this is the case the exit code of the application is available in -// |*exit_code|. -BASE_EXPORT bool GetAppOutputWithExitCode(const CommandLine& cl, - std::string* output, int* exit_code); - -#if defined(OS_WIN) -// A Windows-specific version of GetAppOutput that takes a command line string -// instead of a CommandLine object. Useful for situations where you need to -// control the command line arguments directly. -BASE_EXPORT bool GetAppOutput(const StringPiece16& cl, std::string* output); -#elif defined(OS_POSIX) -// A POSIX-specific version of GetAppOutput that takes an argv array -// instead of a CommandLine. Useful for situations where you need to -// control the command line arguments directly. -BASE_EXPORT bool GetAppOutput(const std::vector<std::string>& argv, - std::string* output); - -// Like the above POSIX-specific version of GetAppOutput, but also includes -// stderr. -BASE_EXPORT bool GetAppOutputAndError(const std::vector<std::string>& argv, - std::string* output); -#endif // defined(OS_WIN) - -// If supported on the platform, and the user has sufficent rights, increase -// the current process's scheduling priority to a high priority. -BASE_EXPORT void RaiseProcessToHighPriority(); - -#if defined(OS_MACOSX) -// An implementation of LaunchProcess() that uses posix_spawn() instead of -// fork()+exec(). This does not support the |pre_exec_delegate| and -// |current_directory| options. -Process LaunchProcessPosixSpawn(const std::vector<std::string>& argv, - const LaunchOptions& options); - -// Restore the default exception handler, setting it to Apple Crash Reporter -// (ReportCrash). When forking and execing a new process, the child will -// inherit the parent's exception ports, which may be set to the Breakpad -// instance running inside the parent. The parent's Breakpad instance should -// not handle the child's exceptions. Calling RestoreDefaultExceptionHandler -// in the child after forking will restore the standard exception handler. -// See http://crbug.com/20371/ for more details. -void RestoreDefaultExceptionHandler(); -#endif // defined(OS_MACOSX) - -// Creates a LaunchOptions object suitable for launching processes in a test -// binary. This should not be called in production/released code. -BASE_EXPORT LaunchOptions LaunchOptionsForTest(); - -#if defined(OS_LINUX) || defined(OS_NACL_NONSFI) -// A wrapper for clone with fork-like behavior, meaning that it returns the -// child's pid in the parent and 0 in the child. |flags|, |ptid|, and |ctid| are -// as in the clone system call (the CLONE_VM flag is not supported). -// -// This function uses the libc clone wrapper (which updates libc's pid cache) -// internally, so callers may expect things like getpid() to work correctly -// after in both the child and parent. -// -// As with fork(), callers should be extremely careful when calling this while -// multiple threads are running, since at the time the fork happened, the -// threads could have been in any state (potentially holding locks, etc.). -// Callers should most likely call execve() in the child soon after calling -// this. -// -// It is unsafe to use any pthread APIs after ForkWithFlags(). -// However, performing an exec() will lift this restriction. -BASE_EXPORT pid_t ForkWithFlags(unsigned long flags, pid_t* ptid, pid_t* ctid); -#endif - -} // namespace base - -#endif // BASE_PROCESS_LAUNCH_H_
diff --git a/base/process/launch_mac.cc b/base/process/launch_mac.cc deleted file mode 100644 index d9a24cc..0000000 --- a/base/process/launch_mac.cc +++ /dev/null
@@ -1,176 +0,0 @@ -// Copyright (c) 2012 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 "base/process/launch.h" - -#include <crt_externs.h> -#include <mach/mach.h> -#include <spawn.h> -#include <string.h> -#include <sys/wait.h> - -#include "base/logging.h" -#include "base/posix/eintr_wrapper.h" - -namespace base { - -namespace { - -// DPSXCHECK is a Debug Posix Spawn Check macro. The posix_spawn* family of -// functions return an errno value, as opposed to setting errno directly. This -// macro emulates a DPCHECK(). -#define DPSXCHECK(expr) \ - do { \ - int rv = (expr); \ - DCHECK_EQ(rv, 0) << #expr << ": -" << rv << " " << strerror(rv); \ - } while (0) - -class PosixSpawnAttr { - public: - PosixSpawnAttr() { DPSXCHECK(posix_spawnattr_init(&attr_)); } - - ~PosixSpawnAttr() { DPSXCHECK(posix_spawnattr_destroy(&attr_)); } - - posix_spawnattr_t* get() { return &attr_; } - - private: - posix_spawnattr_t attr_; -}; - -class PosixSpawnFileActions { - public: - PosixSpawnFileActions() { - DPSXCHECK(posix_spawn_file_actions_init(&file_actions_)); - } - - ~PosixSpawnFileActions() { - DPSXCHECK(posix_spawn_file_actions_destroy(&file_actions_)); - } - - void Open(int filedes, const char* path, int mode) { - DPSXCHECK(posix_spawn_file_actions_addopen(&file_actions_, filedes, path, - mode, 0)); - } - - void Dup2(int filedes, int newfiledes) { - DPSXCHECK( - posix_spawn_file_actions_adddup2(&file_actions_, filedes, newfiledes)); - } - - void Inherit(int filedes) { - DPSXCHECK(posix_spawn_file_actions_addinherit_np(&file_actions_, filedes)); - } - - const posix_spawn_file_actions_t* get() const { return &file_actions_; } - - private: - posix_spawn_file_actions_t file_actions_; - - DISALLOW_COPY_AND_ASSIGN(PosixSpawnFileActions); -}; - -} // namespace - -void RestoreDefaultExceptionHandler() { - // This function is tailored to remove the Breakpad exception handler. - // exception_mask matches s_exception_mask in - // third_party/breakpad/breakpad/src/client/mac/handler/exception_handler.cc - const exception_mask_t exception_mask = EXC_MASK_BAD_ACCESS | - EXC_MASK_BAD_INSTRUCTION | - EXC_MASK_ARITHMETIC | - EXC_MASK_BREAKPOINT; - - // Setting the exception port to MACH_PORT_NULL may not be entirely - // kosher to restore the default exception handler, but in practice, - // it results in the exception port being set to Apple Crash Reporter, - // the desired behavior. - task_set_exception_ports(mach_task_self(), exception_mask, MACH_PORT_NULL, - EXCEPTION_DEFAULT, THREAD_STATE_NONE); -} - -Process LaunchProcessPosixSpawn(const std::vector<std::string>& argv, - const LaunchOptions& options) { - DCHECK(!options.pre_exec_delegate) - << "LaunchProcessPosixSpawn does not support PreExecDelegate"; - DCHECK(options.current_directory.empty()) - << "LaunchProcessPosixSpawn does not support current_directory"; - - PosixSpawnAttr attr; - - short flags = POSIX_SPAWN_CLOEXEC_DEFAULT; - if (options.new_process_group) { - flags |= POSIX_SPAWN_SETPGROUP; - DPSXCHECK(posix_spawnattr_setpgroup(attr.get(), 0)); - } - DPSXCHECK(posix_spawnattr_setflags(attr.get(), flags)); - - PosixSpawnFileActions file_actions; - - // Process file descriptors for the child. By default, LaunchProcess will - // open stdin to /dev/null and inherit stdout and stderr. - bool inherit_stdout = true, inherit_stderr = true; - bool null_stdin = true; - for (const auto& dup2_pair : options.fds_to_remap) { - if (dup2_pair.second == STDIN_FILENO) { - null_stdin = false; - } else if (dup2_pair.second == STDOUT_FILENO) { - inherit_stdout = false; - } else if (dup2_pair.second == STDERR_FILENO) { - inherit_stderr = false; - } - - if (dup2_pair.first == dup2_pair.second) { - file_actions.Inherit(dup2_pair.second); - } else { - file_actions.Dup2(dup2_pair.first, dup2_pair.second); - } - } - - if (null_stdin) { - file_actions.Open(STDIN_FILENO, "/dev/null", O_RDONLY); - } - if (inherit_stdout) { - file_actions.Inherit(STDOUT_FILENO); - } - if (inherit_stderr) { - file_actions.Inherit(STDERR_FILENO); - } - - std::vector<char*> argv_cstr; - argv_cstr.reserve(argv.size() + 1); - for (const auto& arg : argv) - argv_cstr.push_back(const_cast<char*>(arg.c_str())); - argv_cstr.push_back(nullptr); - - std::unique_ptr<char* []> owned_environ; - char** new_environ = options.clear_environ ? nullptr : *_NSGetEnviron(); - if (!options.environ.empty()) { - owned_environ = AlterEnvironment(new_environ, options.environ); - new_environ = owned_environ.get(); - } - - const char* executable_path = !options.real_path.empty() - ? options.real_path.value().c_str() - : argv_cstr[0]; - - // Use posix_spawnp as some callers expect to have PATH consulted. - pid_t pid; - int rv = posix_spawnp(&pid, executable_path, file_actions.get(), attr.get(), - &argv_cstr[0], new_environ); - - if (rv != 0) { - DLOG(ERROR) << "posix_spawnp(" << executable_path << "): -" << rv << " " - << strerror(rv); - return Process(); - } - - if (options.wait) { - pid_t ret = HANDLE_EINTR(waitpid(pid, nullptr, 0)); - DPCHECK(ret > 0); - } - - return Process(pid); -} - -} // namespace base
diff --git a/base/process/launch_posix.cc b/base/process/launch_posix.cc deleted file mode 100644 index 2369802..0000000 --- a/base/process/launch_posix.cc +++ /dev/null
@@ -1,717 +0,0 @@ -// Copyright (c) 2012 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 "base/process/launch.h" - -#include <dirent.h> -#include <errno.h> -#include <fcntl.h> -#include <sched.h> -#include <setjmp.h> -#include <signal.h> -#include <stddef.h> -#include <stdint.h> -#include <stdlib.h> -#include <sys/resource.h> -#include <sys/syscall.h> -#include <sys/time.h> -#include <sys/types.h> -#include <sys/wait.h> -#include <unistd.h> - -#include <iterator> -#include <limits> -#include <memory> -#include <set> - -#include "base/command_line.h" -#include "base/compiler_specific.h" -#include "base/files/dir_reader_posix.h" -#include "base/files/file_util.h" -#include "base/files/scoped_file.h" -#include "base/logging.h" -#include "base/metrics/histogram_macros.h" -#include "base/posix/eintr_wrapper.h" -#include "base/process/process.h" -#include "base/process/process_metrics.h" -#include "base/strings/stringprintf.h" -#include "base/synchronization/waitable_event.h" -#include "base/threading/platform_thread.h" -#include "base/time/time.h" -#include "build_config.h" - -#if defined(OS_LINUX) || defined(OS_AIX) -#include <sys/prctl.h> -#endif - -#if defined(OS_MACOSX) -#include <crt_externs.h> -#include <sys/event.h> - -#include "base/feature_list.h" -#else -extern char** environ; -#endif - -namespace base { - -// Friend and derived class of ScopedAllowBaseSyncPrimitives which allows -// GetAppOutputInternal() to join a process. GetAppOutputInternal() can't itself -// be a friend of ScopedAllowBaseSyncPrimitives because it is in the anonymous -// namespace. -class GetAppOutputScopedAllowBaseSyncPrimitives - : public base::ScopedAllowBaseSyncPrimitives {}; - -#if !defined(OS_NACL_NONSFI) - -namespace { - -#if defined(OS_MACOSX) -const Feature kMacLaunchProcessPosixSpawn{"MacLaunchProcessPosixSpawn", - FEATURE_ENABLED_BY_DEFAULT}; -#endif - -// Get the process's "environment" (i.e. the thing that setenv/getenv -// work with). -char** GetEnvironment() { -#if defined(OS_MACOSX) - return *_NSGetEnviron(); -#else - return environ; -#endif -} - -// Set the process's "environment" (i.e. the thing that setenv/getenv -// work with). -void SetEnvironment(char** env) { -#if defined(OS_MACOSX) - *_NSGetEnviron() = env; -#else - environ = env; -#endif -} - -// Set the calling thread's signal mask to new_sigmask and return -// the previous signal mask. -sigset_t SetSignalMask(const sigset_t& new_sigmask) { - sigset_t old_sigmask; - RAW_CHECK(pthread_sigmask(SIG_SETMASK, &new_sigmask, &old_sigmask) == 0); - return old_sigmask; -} - -#if (!defined(OS_LINUX) && !defined(OS_AIX)) || \ - (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__)) -void ResetChildSignalHandlersToDefaults() { - // The previous signal handlers are likely to be meaningless in the child's - // context so we reset them to the defaults for now. http://crbug.com/44953 - // These signal handlers are set up at least in browser_main_posix.cc: - // BrowserMainPartsPosix::PreEarlyInitialization and stack_trace_posix.cc: - // EnableInProcessStackDumping. - signal(SIGHUP, SIG_DFL); - signal(SIGINT, SIG_DFL); - signal(SIGILL, SIG_DFL); - signal(SIGABRT, SIG_DFL); - signal(SIGFPE, SIG_DFL); - signal(SIGBUS, SIG_DFL); - signal(SIGSEGV, SIG_DFL); - signal(SIGSYS, SIG_DFL); - signal(SIGTERM, SIG_DFL); -} - -#else - -// TODO(jln): remove the Linux special case once kernels are fixed. - -// Internally the kernel makes sigset_t an array of long large enough to have -// one bit per signal. -typedef uint64_t kernel_sigset_t; - -// This is what struct sigaction looks like to the kernel at least on X86 and -// ARM. MIPS, for instance, is very different. -struct kernel_sigaction { - void* k_sa_handler; // For this usage it only needs to be a generic pointer. - unsigned long k_sa_flags; - void* k_sa_restorer; // For this usage it only needs to be a generic pointer. - kernel_sigset_t k_sa_mask; -}; - -// glibc's sigaction() will prevent access to sa_restorer, so we need to roll -// our own. -int sys_rt_sigaction(int sig, const struct kernel_sigaction* act, - struct kernel_sigaction* oact) { - return syscall(SYS_rt_sigaction, sig, act, oact, sizeof(kernel_sigset_t)); -} - -// This function is intended to be used in between fork() and execve() and will -// reset all signal handlers to the default. -// The motivation for going through all of them is that sa_restorer can leak -// from parents and help defeat ASLR on buggy kernels. We reset it to null. -// See crbug.com/177956. -void ResetChildSignalHandlersToDefaults(void) { - for (int signum = 1; ; ++signum) { - struct kernel_sigaction act = {nullptr}; - int sigaction_get_ret = sys_rt_sigaction(signum, nullptr, &act); - if (sigaction_get_ret && errno == EINVAL) { -#if !defined(NDEBUG) - // Linux supports 32 real-time signals from 33 to 64. - // If the number of signals in the Linux kernel changes, someone should - // look at this code. - const int kNumberOfSignals = 64; - RAW_CHECK(signum == kNumberOfSignals + 1); -#endif // !defined(NDEBUG) - break; - } - // All other failures are fatal. - if (sigaction_get_ret) { - RAW_LOG(FATAL, "sigaction (get) failed."); - } - - // The kernel won't allow to re-set SIGKILL or SIGSTOP. - if (signum != SIGSTOP && signum != SIGKILL) { - act.k_sa_handler = reinterpret_cast<void*>(SIG_DFL); - act.k_sa_restorer = nullptr; - if (sys_rt_sigaction(signum, &act, nullptr)) { - RAW_LOG(FATAL, "sigaction (set) failed."); - } - } -#if !defined(NDEBUG) - // Now ask the kernel again and check that no restorer will leak. - if (sys_rt_sigaction(signum, nullptr, &act) || act.k_sa_restorer) { - RAW_LOG(FATAL, "Cound not fix sa_restorer."); - } -#endif // !defined(NDEBUG) - } -} -#endif // !defined(OS_LINUX) || - // (!defined(__i386__) && !defined(__x86_64__) && !defined(__arm__)) -} // anonymous namespace - -// Functor for |ScopedDIR| (below). -struct ScopedDIRClose { - inline void operator()(DIR* x) const { - if (x) - closedir(x); - } -}; - -// Automatically closes |DIR*|s. -typedef std::unique_ptr<DIR, ScopedDIRClose> ScopedDIR; - -#if defined(OS_LINUX) || defined(OS_AIX) -static const char kFDDir[] = "/proc/self/fd"; -#elif defined(OS_MACOSX) -static const char kFDDir[] = "/dev/fd"; -#endif - -void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) { - // DANGER: no calls to malloc or locks are allowed from now on: - // http://crbug.com/36678 - - // Get the maximum number of FDs possible. - size_t max_fds = GetMaxFds(); - - DirReaderPosix fd_dir(kFDDir); - if (!fd_dir.IsValid()) { - // Fallback case: Try every possible fd. - for (size_t i = 0; i < max_fds; ++i) { - const int fd = static_cast<int>(i); - if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) - continue; - // Cannot use STL iterators here, since debug iterators use locks. - size_t j; - for (j = 0; j < saved_mapping.size(); j++) { - if (fd == saved_mapping[j].dest) - break; - } - if (j < saved_mapping.size()) - continue; - - // Since we're just trying to close anything we can find, - // ignore any error return values of close(). - close(fd); - } - return; - } - - const int dir_fd = fd_dir.fd(); - - for ( ; fd_dir.Next(); ) { - // Skip . and .. entries. - if (fd_dir.name()[0] == '.') - continue; - - char *endptr; - errno = 0; - const long int fd = strtol(fd_dir.name(), &endptr, 10); - if (fd_dir.name()[0] == 0 || *endptr || fd < 0 || errno) - continue; - if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) - continue; - // Cannot use STL iterators here, since debug iterators use locks. - size_t i; - for (i = 0; i < saved_mapping.size(); i++) { - if (fd == saved_mapping[i].dest) - break; - } - if (i < saved_mapping.size()) - continue; - if (fd == dir_fd) - continue; - - int ret = IGNORE_EINTR(close(fd)); - DPCHECK(ret == 0); - } -} - -Process LaunchProcess(const CommandLine& cmdline, - const LaunchOptions& options) { - return LaunchProcess(cmdline.argv(), options); -} - -Process LaunchProcess(const std::vector<std::string>& argv, - const LaunchOptions& options) { - TRACE_EVENT0("base", "LaunchProcess"); -#if defined(OS_MACOSX) - if (FeatureList::IsEnabled(kMacLaunchProcessPosixSpawn)) { - // TODO(rsesek): Do this unconditionally. There is one user for each of - // these two options. https://crbug.com/179923. - if (!options.pre_exec_delegate && options.current_directory.empty()) - return LaunchProcessPosixSpawn(argv, options); - } -#endif - - InjectiveMultimap fd_shuffle1; - InjectiveMultimap fd_shuffle2; - fd_shuffle1.reserve(options.fds_to_remap.size()); - fd_shuffle2.reserve(options.fds_to_remap.size()); - - std::vector<char*> argv_cstr; - argv_cstr.reserve(argv.size() + 1); - for (const auto& arg : argv) - argv_cstr.push_back(const_cast<char*>(arg.c_str())); - argv_cstr.push_back(nullptr); - - std::unique_ptr<char* []> new_environ; - char* const empty_environ = nullptr; - char* const* old_environ = GetEnvironment(); - if (options.clear_environ) - old_environ = &empty_environ; - if (!options.environ.empty()) - new_environ = AlterEnvironment(old_environ, options.environ); - - sigset_t full_sigset; - sigfillset(&full_sigset); - const sigset_t orig_sigmask = SetSignalMask(full_sigset); - - const char* current_directory = nullptr; - if (!options.current_directory.empty()) { - current_directory = options.current_directory.value().c_str(); - } - - pid_t pid; - base::TimeTicks before_fork = TimeTicks::Now(); -#if defined(OS_LINUX) || defined(OS_AIX) - if (options.clone_flags) { - // Signal handling in this function assumes the creation of a new - // process, so we check that a thread is not being created by mistake - // and that signal handling follows the process-creation rules. - RAW_CHECK( - !(options.clone_flags & (CLONE_SIGHAND | CLONE_THREAD | CLONE_VM))); - - // We specify a null ptid and ctid. - RAW_CHECK( - !(options.clone_flags & - (CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | CLONE_PARENT_SETTID))); - - // Since we use waitpid, we do not support custom termination signals in the - // clone flags. - RAW_CHECK((options.clone_flags & 0xff) == 0); - - pid = ForkWithFlags(options.clone_flags | SIGCHLD, nullptr, nullptr); - } else -#endif - { - pid = fork(); - } - - // Always restore the original signal mask in the parent. - if (pid != 0) { - base::TimeTicks after_fork = TimeTicks::Now(); - SetSignalMask(orig_sigmask); - - base::TimeDelta fork_time = after_fork - before_fork; - UMA_HISTOGRAM_TIMES("MPArch.ForkTime", fork_time); - } - - if (pid < 0) { - DPLOG(ERROR) << "fork"; - return Process(); - } else if (pid == 0) { - // Child process - - // DANGER: no calls to malloc or locks are allowed from now on: - // http://crbug.com/36678 - - // DANGER: fork() rule: in the child, if you don't end up doing exec*(), - // you call _exit() instead of exit(). This is because _exit() does not - // call any previously-registered (in the parent) exit handlers, which - // might do things like block waiting for threads that don't even exist - // in the child. - - // If a child process uses the readline library, the process block forever. - // In BSD like OSes including OS X it is safe to assign /dev/null as stdin. - // See http://crbug.com/56596. - base::ScopedFD null_fd(HANDLE_EINTR(open("/dev/null", O_RDONLY))); - if (!null_fd.is_valid()) { - RAW_LOG(ERROR, "Failed to open /dev/null"); - _exit(127); - } - - int new_fd = HANDLE_EINTR(dup2(null_fd.get(), STDIN_FILENO)); - if (new_fd != STDIN_FILENO) { - RAW_LOG(ERROR, "Failed to dup /dev/null for stdin"); - _exit(127); - } - - if (options.new_process_group) { - // Instead of inheriting the process group ID of the parent, the child - // starts off a new process group with pgid equal to its process ID. - if (setpgid(0, 0) < 0) { - RAW_LOG(ERROR, "setpgid failed"); - _exit(127); - } - } - - if (options.maximize_rlimits) { - // Some resource limits need to be maximal in this child. - for (size_t i = 0; i < options.maximize_rlimits->size(); ++i) { - const int resource = (*options.maximize_rlimits)[i]; - struct rlimit limit; - if (getrlimit(resource, &limit) < 0) { - RAW_LOG(WARNING, "getrlimit failed"); - } else if (limit.rlim_cur < limit.rlim_max) { - limit.rlim_cur = limit.rlim_max; - if (setrlimit(resource, &limit) < 0) { - RAW_LOG(WARNING, "setrlimit failed"); - } - } - } - } - -#if defined(OS_MACOSX) - RestoreDefaultExceptionHandler(); -#endif // defined(OS_MACOSX) - - ResetChildSignalHandlersToDefaults(); - SetSignalMask(orig_sigmask); - -#if 0 - // When debugging it can be helpful to check that we really aren't making - // any hidden calls to malloc. - void *malloc_thunk = - reinterpret_cast<void*>(reinterpret_cast<intptr_t>(malloc) & ~4095); - mprotect(malloc_thunk, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); - memset(reinterpret_cast<void*>(malloc), 0xff, 8); -#endif // 0 - - // Cannot use STL iterators here, since debug iterators use locks. - for (size_t i = 0; i < options.fds_to_remap.size(); ++i) { - const FileHandleMappingVector::value_type& value = - options.fds_to_remap[i]; - fd_shuffle1.push_back(InjectionArc(value.first, value.second, false)); - fd_shuffle2.push_back(InjectionArc(value.first, value.second, false)); - } - - if (!options.environ.empty() || options.clear_environ) - SetEnvironment(new_environ.get()); - - // fd_shuffle1 is mutated by this call because it cannot malloc. - if (!ShuffleFileDescriptors(&fd_shuffle1)) - _exit(127); - - CloseSuperfluousFds(fd_shuffle2); - - // Set NO_NEW_PRIVS by default. Since NO_NEW_PRIVS only exists in kernel - // 3.5+, do not check the return value of prctl here. -#if defined(OS_LINUX) || defined(OS_AIX) -#ifndef PR_SET_NO_NEW_PRIVS -#define PR_SET_NO_NEW_PRIVS 38 -#endif - if (!options.allow_new_privs) { - if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) && errno != EINVAL) { - // Only log if the error is not EINVAL (i.e. not supported). - RAW_LOG(FATAL, "prctl(PR_SET_NO_NEW_PRIVS) failed"); - } - } - - if (options.kill_on_parent_death) { - if (prctl(PR_SET_PDEATHSIG, SIGKILL) != 0) { - RAW_LOG(ERROR, "prctl(PR_SET_PDEATHSIG) failed"); - _exit(127); - } - } -#endif - - if (current_directory != nullptr) { - RAW_CHECK(chdir(current_directory) == 0); - } - - if (options.pre_exec_delegate != nullptr) { - options.pre_exec_delegate->RunAsyncSafe(); - } - - const char* executable_path = !options.real_path.empty() ? - options.real_path.value().c_str() : argv_cstr[0]; - - execvp(executable_path, argv_cstr.data()); - - RAW_LOG(ERROR, "LaunchProcess: failed to execvp:"); - RAW_LOG(ERROR, argv_cstr[0]); - _exit(127); - } else { - // Parent process - if (options.wait) { - pid_t ret = HANDLE_EINTR(waitpid(pid, nullptr, 0)); - DPCHECK(ret > 0); - } - } - - return Process(pid); -} - -void RaiseProcessToHighPriority() { - // On POSIX, we don't actually do anything here. We could try to nice() or - // setpriority() or sched_getscheduler, but these all require extra rights. -} - -// Executes the application specified by |argv| and wait for it to exit. Stores -// the output (stdout) in |output|. If |do_search_path| is set, it searches the -// path for the application; in that case, |envp| must be null, and it will use -// the current environment. If |do_search_path| is false, |argv[0]| should fully -// specify the path of the application, and |envp| will be used as the -// environment. If |include_stderr| is true, includes stderr otherwise redirects -// it to /dev/null. -// The return value of the function indicates success or failure. In the case of -// success, the application exit code will be returned in |*exit_code|, which -// should be checked to determine if the application ran successfully. -static bool GetAppOutputInternal( - const std::vector<std::string>& argv, - char* const envp[], - bool include_stderr, - std::string* output, - bool do_search_path, - int* exit_code) { - // exit_code must be supplied so calling function can determine success. - DCHECK(exit_code); - *exit_code = EXIT_FAILURE; - - // Declare and call reserve() here before calling fork() because the child - // process cannot allocate memory. - std::vector<char*> argv_cstr; - argv_cstr.reserve(argv.size() + 1); - InjectiveMultimap fd_shuffle1; - InjectiveMultimap fd_shuffle2; - fd_shuffle1.reserve(3); - fd_shuffle2.reserve(3); - - // Either |do_search_path| should be false or |envp| should be null, but not - // both. - DCHECK(!do_search_path ^ !envp); - - int pipe_fd[2]; - if (pipe(pipe_fd) < 0) - return false; - - pid_t pid = fork(); - switch (pid) { - case -1: { - // error - close(pipe_fd[0]); - close(pipe_fd[1]); - return false; - } - case 0: { - // child - // - // DANGER: no calls to malloc or locks are allowed from now on: - // http://crbug.com/36678 - -#if defined(OS_MACOSX) - RestoreDefaultExceptionHandler(); -#endif - - // Obscure fork() rule: in the child, if you don't end up doing exec*(), - // you call _exit() instead of exit(). This is because _exit() does not - // call any previously-registered (in the parent) exit handlers, which - // might do things like block waiting for threads that don't even exist - // in the child. - int dev_null = open("/dev/null", O_WRONLY); - if (dev_null < 0) - _exit(127); - - fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true)); - fd_shuffle1.push_back(InjectionArc(include_stderr ? pipe_fd[1] : dev_null, - STDERR_FILENO, true)); - fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true)); - // Adding another element here? Remeber to increase the argument to - // reserve(), above. - - for (size_t i = 0; i < fd_shuffle1.size(); ++i) - fd_shuffle2.push_back(fd_shuffle1[i]); - - if (!ShuffleFileDescriptors(&fd_shuffle1)) - _exit(127); - - CloseSuperfluousFds(fd_shuffle2); - - for (const auto& arg : argv) - argv_cstr.push_back(const_cast<char*>(arg.c_str())); - argv_cstr.push_back(nullptr); - - if (do_search_path) - execvp(argv_cstr[0], argv_cstr.data()); - else - execve(argv_cstr[0], argv_cstr.data(), envp); - _exit(127); - } - default: { - // parent - // - // Close our writing end of pipe now. Otherwise later read would not - // be able to detect end of child's output (in theory we could still - // write to the pipe). - close(pipe_fd[1]); - - output->clear(); - - while (true) { - char buffer[256]; - ssize_t bytes_read = - HANDLE_EINTR(read(pipe_fd[0], buffer, sizeof(buffer))); - if (bytes_read <= 0) - break; - output->append(buffer, bytes_read); - } - close(pipe_fd[0]); - - // Always wait for exit code (even if we know we'll declare - // GOT_MAX_OUTPUT). - Process process(pid); - // A process launched with GetAppOutput*() usually doesn't wait on the - // process that launched it and thus chances of deadlock are low. - GetAppOutputScopedAllowBaseSyncPrimitives allow_base_sync_primitives; - return process.WaitForExit(exit_code); - } - } -} - -bool GetAppOutput(const CommandLine& cl, std::string* output) { - return GetAppOutput(cl.argv(), output); -} - -bool GetAppOutput(const std::vector<std::string>& argv, std::string* output) { - // Run |execve()| with the current environment. - int exit_code; - bool result = - GetAppOutputInternal(argv, nullptr, false, output, true, &exit_code); - return result && exit_code == EXIT_SUCCESS; -} - -bool GetAppOutputAndError(const CommandLine& cl, std::string* output) { - // Run |execve()| with the current environment. - int exit_code; - bool result = - GetAppOutputInternal(cl.argv(), nullptr, true, output, true, &exit_code); - return result && exit_code == EXIT_SUCCESS; -} - -bool GetAppOutputAndError(const std::vector<std::string>& argv, - std::string* output) { - int exit_code; - bool result = - GetAppOutputInternal(argv, nullptr, true, output, true, &exit_code); - return result && exit_code == EXIT_SUCCESS; -} - -bool GetAppOutputWithExitCode(const CommandLine& cl, - std::string* output, - int* exit_code) { - // Run |execve()| with the current environment. - return GetAppOutputInternal(cl.argv(), nullptr, false, output, true, - exit_code); -} - -#endif // !defined(OS_NACL_NONSFI) - -#if defined(OS_LINUX) || defined(OS_NACL_NONSFI) || defined(OS_AIX) -namespace { - -// This function runs on the stack specified on the clone call. It uses longjmp -// to switch back to the original stack so the child can return from sys_clone. -int CloneHelper(void* arg) { - jmp_buf* env_ptr = reinterpret_cast<jmp_buf*>(arg); - longjmp(*env_ptr, 1); - - // Should not be reached. - RAW_CHECK(false); - return 1; -} - -// This function is noinline to ensure that stack_buf is below the stack pointer -// that is saved when setjmp is called below. This is needed because when -// compiled with FORTIFY_SOURCE, glibc's longjmp checks that the stack is moved -// upwards. See crbug.com/442912 for more details. -#if defined(ADDRESS_SANITIZER) -// Disable AddressSanitizer instrumentation for this function to make sure -// |stack_buf| is allocated on thread stack instead of ASan's fake stack. -// Under ASan longjmp() will attempt to clean up the area between the old and -// new stack pointers and print a warning that may confuse the user. -__attribute__((no_sanitize_address)) -#endif -NOINLINE pid_t CloneAndLongjmpInChild(unsigned long flags, - pid_t* ptid, - pid_t* ctid, - jmp_buf* env) { - // We use the libc clone wrapper instead of making the syscall - // directly because making the syscall may fail to update the libc's - // internal pid cache. The libc interface unfortunately requires - // specifying a new stack, so we use setjmp/longjmp to emulate - // fork-like behavior. - alignas(16) char stack_buf[PTHREAD_STACK_MIN]; -#if defined(ARCH_CPU_X86_FAMILY) || defined(ARCH_CPU_ARM_FAMILY) || \ - defined(ARCH_CPU_MIPS_FAMILY) || defined(ARCH_CPU_S390_FAMILY) || \ - defined(ARCH_CPU_PPC64_FAMILY) - // The stack grows downward. - void* stack = stack_buf + sizeof(stack_buf); -#else -#error "Unsupported architecture" -#endif - return clone(&CloneHelper, stack, flags, env, ptid, nullptr, ctid); -} - -} // anonymous namespace - -pid_t ForkWithFlags(unsigned long flags, pid_t* ptid, pid_t* ctid) { - const bool clone_tls_used = flags & CLONE_SETTLS; - const bool invalid_ctid = - (flags & (CLONE_CHILD_SETTID | CLONE_CHILD_CLEARTID)) && !ctid; - const bool invalid_ptid = (flags & CLONE_PARENT_SETTID) && !ptid; - - // We do not support CLONE_VM. - const bool clone_vm_used = flags & CLONE_VM; - - if (clone_tls_used || invalid_ctid || invalid_ptid || clone_vm_used) { - RAW_LOG(FATAL, "Invalid usage of ForkWithFlags"); - } - - jmp_buf env; - if (setjmp(env) == 0) { - return CloneAndLongjmpInChild(flags, ptid, ctid, &env); - } - - return 0; -} -#endif // defined(OS_LINUX) || defined(OS_NACL_NONSFI) - -} // namespace base
diff --git a/base/process/launch_unittest_win.cc b/base/process/launch_unittest_win.cc deleted file mode 100644 index 1b060c5..0000000 --- a/base/process/launch_unittest_win.cc +++ /dev/null
@@ -1,24 +0,0 @@ -// Copyright 2017 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 "base/process/launch.h" - -#include "base/command_line.h" -#include "base/files/file_path.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(LaunchWinTest, GetAppOutputWithExitCodeShouldReturnExitCode) { - CommandLine cl(FilePath(FILE_PATH_LITERAL("cmd"))); - cl.AppendArg("/c"); - cl.AppendArg("this-is-not-an-application"); - std::string output; - int exit_code; - ASSERT_TRUE(GetAppOutputWithExitCode(cl, &output, &exit_code)); - ASSERT_TRUE(output.empty()); - ASSERT_EQ(1, exit_code); -} - -} // namespace
diff --git a/base/process/launch_win.cc b/base/process/launch_win.cc deleted file mode 100644 index f24b6dd..0000000 --- a/base/process/launch_win.cc +++ /dev/null
@@ -1,389 +0,0 @@ -// Copyright (c) 2012 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 "base/process/launch.h" - -#include <fcntl.h> -#include <io.h> -#include <shellapi.h> -#include <windows.h> -#include <userenv.h> -#include <psapi.h> - -#include <ios> -#include <limits> - -#include "base/bind.h" -#include "base/bind_helpers.h" -#include "base/command_line.h" -#include "base/logging.h" -#include "base/process/kill.h" -#include "base/strings/utf_string_conversions.h" -#include "base/win/scoped_handle.h" -#include "base/win/scoped_process_information.h" -#include "base/win/startup_information.h" -#include "base/win/windows_version.h" - -namespace base { - -namespace { - -bool GetAppOutputInternal(const StringPiece16& cl, - bool include_stderr, - std::string* output, - int* exit_code) { - HANDLE out_read = nullptr; - HANDLE out_write = nullptr; - - SECURITY_ATTRIBUTES sa_attr; - // Set the bInheritHandle flag so pipe handles are inherited. - sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES); - sa_attr.bInheritHandle = TRUE; - sa_attr.lpSecurityDescriptor = nullptr; - - // Create the pipe for the child process's STDOUT. - if (!CreatePipe(&out_read, &out_write, &sa_attr, 0)) { - NOTREACHED() << "Failed to create pipe"; - return false; - } - - // Ensure we don't leak the handles. - win::ScopedHandle scoped_out_read(out_read); - win::ScopedHandle scoped_out_write(out_write); - - // Ensure the read handles to the pipes are not inherited. - if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) { - NOTREACHED() << "Failed to disabled pipe inheritance"; - return false; - } - - FilePath::StringType writable_command_line_string; - writable_command_line_string.assign(cl.data(), cl.size()); - - STARTUPINFO start_info = {}; - - start_info.cb = sizeof(STARTUPINFO); - start_info.hStdOutput = out_write; - // Keep the normal stdin. - start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); - if (include_stderr) { - start_info.hStdError = out_write; - } else { - start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); - } - start_info.dwFlags |= STARTF_USESTDHANDLES; - - // Create the child process. - PROCESS_INFORMATION temp_process_info = {}; - if (!CreateProcess(nullptr, &writable_command_line_string[0], nullptr, - nullptr, - TRUE, // Handles are inherited. - 0, nullptr, nullptr, &start_info, &temp_process_info)) { - NOTREACHED() << "Failed to start process"; - return false; - } - - base::win::ScopedProcessInformation proc_info(temp_process_info); - - // Close our writing end of pipe now. Otherwise later read would not be able - // to detect end of child's output. - scoped_out_write.Close(); - - // Read output from the child process's pipe for STDOUT - const int kBufferSize = 1024; - char buffer[kBufferSize]; - - for (;;) { - DWORD bytes_read = 0; - BOOL success = - ::ReadFile(out_read, buffer, kBufferSize, &bytes_read, nullptr); - if (!success || bytes_read == 0) - break; - output->append(buffer, bytes_read); - } - - // Let's wait for the process to finish. - WaitForSingleObject(proc_info.process_handle(), INFINITE); - - base::TerminationStatus status = GetTerminationStatus( - proc_info.process_handle(), exit_code); - return status != base::TERMINATION_STATUS_PROCESS_CRASHED && - status != base::TERMINATION_STATUS_ABNORMAL_TERMINATION; -} - -} // namespace - -void RouteStdioToConsole(bool create_console_if_not_found) { - // Don't change anything if stdout or stderr already point to a - // valid stream. - // - // If we are running under Buildbot or under Cygwin's default - // terminal (mintty), stderr and stderr will be pipe handles. In - // that case, we don't want to open CONOUT$, because its output - // likely does not go anywhere. - // - // We don't use GetStdHandle() to check stdout/stderr here because - // it can return dangling IDs of handles that were never inherited - // by this process. These IDs could have been reused by the time - // this function is called. The CRT checks the validity of - // stdout/stderr on startup (before the handle IDs can be reused). - // _fileno(stdout) will return -2 (_NO_CONSOLE_FILENO) if stdout was - // invalid. - if (_fileno(stdout) >= 0 || _fileno(stderr) >= 0) { - // _fileno was broken for SUBSYSTEM:WINDOWS from VS2010 to VS2012/2013. - // http://crbug.com/358267. Confirm that the underlying HANDLE is valid - // before aborting. - - intptr_t stdout_handle = _get_osfhandle(_fileno(stdout)); - intptr_t stderr_handle = _get_osfhandle(_fileno(stderr)); - if (stdout_handle >= 0 || stderr_handle >= 0) - return; - } - - if (!AttachConsole(ATTACH_PARENT_PROCESS)) { - unsigned int result = GetLastError(); - // Was probably already attached. - if (result == ERROR_ACCESS_DENIED) - return; - // Don't bother creating a new console for each child process if the - // parent process is invalid (eg: crashed). - if (result == ERROR_GEN_FAILURE) - return; - if (create_console_if_not_found) { - // Make a new console if attaching to parent fails with any other error. - // It should be ERROR_INVALID_HANDLE at this point, which means the - // browser was likely not started from a console. - AllocConsole(); - } else { - return; - } - } - - // Arbitrary byte count to use when buffering output lines. More - // means potential waste, less means more risk of interleaved - // log-lines in output. - enum { kOutputBufferSize = 64 * 1024 }; - - if (freopen("CONOUT$", "w", stdout)) { - setvbuf(stdout, nullptr, _IOLBF, kOutputBufferSize); - // Overwrite FD 1 for the benefit of any code that uses this FD - // directly. This is safe because the CRT allocates FDs 0, 1 and - // 2 at startup even if they don't have valid underlying Windows - // handles. This means we won't be overwriting an FD created by - // _open() after startup. - _dup2(_fileno(stdout), 1); - } - if (freopen("CONOUT$", "w", stderr)) { - setvbuf(stderr, nullptr, _IOLBF, kOutputBufferSize); - _dup2(_fileno(stderr), 2); - } - - // Fix all cout, wcout, cin, wcin, cerr, wcerr, clog and wclog. - std::ios::sync_with_stdio(); -} - -Process LaunchProcess(const CommandLine& cmdline, - const LaunchOptions& options) { - return LaunchProcess(cmdline.GetCommandLineString(), options); -} - -Process LaunchProcess(const string16& cmdline, - const LaunchOptions& options) { - win::StartupInformation startup_info_wrapper; - STARTUPINFO* startup_info = startup_info_wrapper.startup_info(); - - bool inherit_handles = options.inherit_mode == LaunchOptions::Inherit::kAll; - DWORD flags = 0; - if (!options.handles_to_inherit.empty()) { - DCHECK_EQ(options.inherit_mode, LaunchOptions::Inherit::kSpecific); - - if (options.handles_to_inherit.size() > - std::numeric_limits<DWORD>::max() / sizeof(HANDLE)) { - DLOG(ERROR) << "Too many handles to inherit."; - return Process(); - } - - // Ensure the handles can be inherited. - for (HANDLE handle : options.handles_to_inherit) { - BOOL result = SetHandleInformation(handle, HANDLE_FLAG_INHERIT, - HANDLE_FLAG_INHERIT); - PCHECK(result); - } - - if (!startup_info_wrapper.InitializeProcThreadAttributeList(1)) { - DPLOG(ERROR); - return Process(); - } - - if (!startup_info_wrapper.UpdateProcThreadAttribute( - PROC_THREAD_ATTRIBUTE_HANDLE_LIST, - const_cast<HANDLE*>(&options.handles_to_inherit[0]), - static_cast<DWORD>(options.handles_to_inherit.size() * - sizeof(HANDLE)))) { - DPLOG(ERROR); - return Process(); - } - - inherit_handles = true; - flags |= EXTENDED_STARTUPINFO_PRESENT; - } - - if (options.empty_desktop_name) - startup_info->lpDesktop = const_cast<wchar_t*>(L""); - startup_info->dwFlags = STARTF_USESHOWWINDOW; - startup_info->wShowWindow = options.start_hidden ? SW_HIDE : SW_SHOWNORMAL; - - if (options.stdin_handle || options.stdout_handle || options.stderr_handle) { - DCHECK(inherit_handles); - DCHECK(options.stdin_handle); - DCHECK(options.stdout_handle); - DCHECK(options.stderr_handle); - startup_info->dwFlags |= STARTF_USESTDHANDLES; - startup_info->hStdInput = options.stdin_handle; - startup_info->hStdOutput = options.stdout_handle; - startup_info->hStdError = options.stderr_handle; - } - - const bool launch_suspended = - options.job_handle || options.grant_foreground_privilege; - - if (launch_suspended) - flags |= CREATE_SUSPENDED; - - if (options.job_handle) { - // If this code is run under a debugger, the launched process is - // automatically associated with a job object created by the debugger. - // The CREATE_BREAKAWAY_FROM_JOB flag is used to prevent this on Windows - // releases that do not support nested jobs. - if (win::GetVersion() < win::VERSION_WIN8) - flags |= CREATE_BREAKAWAY_FROM_JOB; - } - - if (options.force_breakaway_from_job_) - flags |= CREATE_BREAKAWAY_FROM_JOB; - - PROCESS_INFORMATION temp_process_info = {}; - - LPCTSTR current_directory = options.current_directory.empty() - ? nullptr - : options.current_directory.value().c_str(); - - string16 writable_cmdline(cmdline); - if (options.as_user) { - flags |= CREATE_UNICODE_ENVIRONMENT; - void* enviroment_block = nullptr; - - if (!CreateEnvironmentBlock(&enviroment_block, options.as_user, FALSE)) { - DPLOG(ERROR); - return Process(); - } - - BOOL launched = CreateProcessAsUser( - options.as_user, nullptr, &writable_cmdline[0], nullptr, nullptr, - inherit_handles, flags, enviroment_block, current_directory, - startup_info, &temp_process_info); - DestroyEnvironmentBlock(enviroment_block); - if (!launched) { - DPLOG(ERROR) << "Command line:" << std::endl << UTF16ToUTF8(cmdline) - << std::endl; - return Process(); - } - } else { - if (!CreateProcess(nullptr, &writable_cmdline[0], nullptr, nullptr, - inherit_handles, flags, nullptr, current_directory, - startup_info, &temp_process_info)) { - DPLOG(ERROR) << "Command line:" << std::endl << UTF16ToUTF8(cmdline) - << std::endl; - return Process(); - } - } - base::win::ScopedProcessInformation process_info(temp_process_info); - - if (options.job_handle && - !AssignProcessToJobObject(options.job_handle, - process_info.process_handle())) { - DPLOG(ERROR) << "Could not AssignProcessToObject"; - Process scoped_process(process_info.TakeProcessHandle()); - scoped_process.Terminate(win::kProcessKilledExitCode, true); - return Process(); - } - - if (options.grant_foreground_privilege && - !AllowSetForegroundWindow(GetProcId(process_info.process_handle()))) { - DPLOG(ERROR) << "Failed to grant foreground privilege to launched process"; - } - - if (launch_suspended) - ResumeThread(process_info.thread_handle()); - - if (options.wait) - WaitForSingleObject(process_info.process_handle(), INFINITE); - - return Process(process_info.TakeProcessHandle()); -} - -Process LaunchElevatedProcess(const CommandLine& cmdline, - const LaunchOptions& options) { - const string16 file = cmdline.GetProgram().value(); - const string16 arguments = cmdline.GetArgumentsString(); - - SHELLEXECUTEINFO shex_info = {}; - shex_info.cbSize = sizeof(shex_info); - shex_info.fMask = SEE_MASK_NOCLOSEPROCESS; - shex_info.hwnd = GetActiveWindow(); - shex_info.lpVerb = L"runas"; - shex_info.lpFile = file.c_str(); - shex_info.lpParameters = arguments.c_str(); - shex_info.lpDirectory = nullptr; - shex_info.nShow = options.start_hidden ? SW_HIDE : SW_SHOWNORMAL; - shex_info.hInstApp = nullptr; - - if (!ShellExecuteEx(&shex_info)) { - DPLOG(ERROR); - return Process(); - } - - if (options.wait) - WaitForSingleObject(shex_info.hProcess, INFINITE); - - return Process(shex_info.hProcess); -} - -bool SetJobObjectLimitFlags(HANDLE job_object, DWORD limit_flags) { - JOBOBJECT_EXTENDED_LIMIT_INFORMATION limit_info = {}; - limit_info.BasicLimitInformation.LimitFlags = limit_flags; - return 0 != SetInformationJobObject( - job_object, - JobObjectExtendedLimitInformation, - &limit_info, - sizeof(limit_info)); -} - -bool GetAppOutput(const CommandLine& cl, std::string* output) { - return GetAppOutput(cl.GetCommandLineString(), output); -} - -bool GetAppOutputAndError(const CommandLine& cl, std::string* output) { - int exit_code; - return GetAppOutputInternal( - cl.GetCommandLineString(), true, output, &exit_code); -} - -bool GetAppOutputWithExitCode(const CommandLine& cl, - std::string* output, - int* exit_code) { - return GetAppOutputInternal( - cl.GetCommandLineString(), false, output, exit_code); -} - -bool GetAppOutput(const StringPiece16& cl, std::string* output) { - int exit_code; - return GetAppOutputInternal(cl, false, output, &exit_code); -} - -void RaiseProcessToHighPriority() { - SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); -} - -} // namespace base
diff --git a/base/process/memory_unittest_mac.h b/base/process/memory_unittest_mac.h deleted file mode 100644 index 4d82a73..0000000 --- a/base/process/memory_unittest_mac.h +++ /dev/null
@@ -1,35 +0,0 @@ -// Copyright (c) 2010 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. - -// This file contains helpers for the process_util_unittest to allow it to fully -// test the Mac code. - -#ifndef BASE_PROCESS_MEMORY_UNITTEST_MAC_H_ -#define BASE_PROCESS_MEMORY_UNITTEST_MAC_H_ - -#include <stddef.h> -#include <sys/types.h> - -#include "build_config.h" - -namespace base { - -// Allocates memory via system allocators. Alas, they take a _signed_ size for -// allocation. -void* AllocateViaCFAllocatorSystemDefault(ssize_t size); -void* AllocateViaCFAllocatorMalloc(ssize_t size); -void* AllocateViaCFAllocatorMallocZone(ssize_t size); - -#if !defined(ARCH_CPU_64_BITS) -// See process_util_unittest_mac.mm for an explanation of why this function -// isn't implemented for the 64-bit environment. - -// Allocates a huge Objective C object. -void* AllocatePsychoticallyBigObjCObject(); - -#endif // !ARCH_CPU_64_BITS - -} // namespace base - -#endif // BASE_PROCESS_MEMORY_UNITTEST_MAC_H_
diff --git a/base/process/memory_unittest_mac.mm b/base/process/memory_unittest_mac.mm deleted file mode 100644 index 7ec7afd..0000000 --- a/base/process/memory_unittest_mac.mm +++ /dev/null
@@ -1,60 +0,0 @@ -// Copyright (c) 2010 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 "base/process/memory_unittest_mac.h" -#include "build_config.h" - -#import <Foundation/Foundation.h> -#include <CoreFoundation/CoreFoundation.h> - -#if !defined(ARCH_CPU_64_BITS) - -// In the 64-bit environment, the Objective-C 2.0 Runtime Reference states -// that sizeof(anInstance) is constrained to 32 bits. That's not necessarily -// "psychotically big" and in fact a 64-bit program is expected to be able to -// successfully allocate an object that large, likely reserving a good deal of -// swap space. The only way to test the behavior of memory exhaustion for -// Objective-C allocation in this environment would be to loop over allocation -// of these large objects, but that would slowly consume all available memory -// and cause swap file proliferation. That's bad, so this behavior isn't -// tested in the 64-bit environment. - -@interface PsychoticallyBigObjCObject : NSObject -{ - // In the 32-bit environment, the compiler limits Objective-C objects to - // < 2GB in size. - int justUnder2Gigs_[(2U * 1024 * 1024 * 1024 - 1) / sizeof(int)]; -} - -@end - -@implementation PsychoticallyBigObjCObject - -@end - -namespace base { - -void* AllocatePsychoticallyBigObjCObject() { - return [[PsychoticallyBigObjCObject alloc] init]; -} - -} // namespace base - -#endif // ARCH_CPU_64_BITS - -namespace base { - -void* AllocateViaCFAllocatorSystemDefault(ssize_t size) { - return CFAllocatorAllocate(kCFAllocatorSystemDefault, size, 0); -} - -void* AllocateViaCFAllocatorMalloc(ssize_t size) { - return CFAllocatorAllocate(kCFAllocatorMalloc, size, 0); -} - -void* AllocateViaCFAllocatorMallocZone(ssize_t size) { - return CFAllocatorAllocate(kCFAllocatorMallocZone, size, 0); -} - -} // namespace base
diff --git a/base/strings/sys_string_conversions_mac_unittest.mm b/base/strings/sys_string_conversions_mac_unittest.mm deleted file mode 100644 index 4750a9a..0000000 --- a/base/strings/sys_string_conversions_mac_unittest.mm +++ /dev/null
@@ -1,21 +0,0 @@ -// Copyright (c) 2012 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. - -#import <Foundation/Foundation.h> - -#include "base/strings/string16.h" -#include "base/strings/sys_string_conversions.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace base { - -TEST(SysStrings, ConversionsFromNSString) { - EXPECT_STREQ("Hello, world!", SysNSStringToUTF8(@"Hello, world!").c_str()); - - // Conversions should be able to handle a NULL value without crashing. - EXPECT_STREQ("", SysNSStringToUTF8(nil).c_str()); - EXPECT_EQ(string16(), SysNSStringToUTF16(nil)); -} - -} // namespace base
diff --git a/build/gen.py b/build/gen.py index 45c3e33..d72f39b 100755 --- a/build/gen.py +++ b/build/gen.py
@@ -551,7 +551,6 @@ 'base/files/file_util_win.cc', 'base/files/file_win.cc', 'base/process/kill_win.cc', - 'base/process/launch_win.cc', 'base/process/memory_win.cc', 'base/process/process_handle_win.cc', 'base/process/process_info_win.cc',
diff --git a/tools/gn/command_args.cc b/tools/gn/command_args.cc index b3c6862..e7721ad 100644 --- a/tools/gn/command_args.cc +++ b/tools/gn/command_args.cc
@@ -13,7 +13,6 @@ #include "base/environment.h" #include "base/files/file_util.h" #include "base/json/json_writer.h" -#include "base/process/launch.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "build_config.h"
diff --git a/tools/gn/exec_process.cc b/tools/gn/exec_process.cc index 1009cec..092178d 100644 --- a/tools/gn/exec_process.cc +++ b/tools/gn/exec_process.cc
@@ -12,7 +12,6 @@ #include "base/files/file_util.h" #include "base/logging.h" #include "base/process/kill.h" -#include "base/process/launch.h" #include "base/process/process.h" #include "build_config.h"
diff --git a/tools/gn/setup.cc b/tools/gn/setup.cc index 8a66259..20b3a6f 100644 --- a/tools/gn/setup.cc +++ b/tools/gn/setup.cc
@@ -16,7 +16,7 @@ #include "base/files/file_path.h" #include "base/files/file_util.h" #include "base/memory/ref_counted.h" -#include "base/process/launch.h" +#include "base/process/kill.h" #include "base/strings/string_split.h" #include "base/strings/string_util.h" #include "base/strings/sys_string_conversions.h" @@ -39,6 +39,7 @@ #if defined(OS_WIN) #include <windows.h> +#include "base/win/scoped_process_information.h" #endif const char kDotfile_Help[] = @@ -189,6 +190,83 @@ #if defined(OS_WIN) +bool GetAppOutput(const base::StringPiece16& cl, std::string* output) { + HANDLE out_read = nullptr; + HANDLE out_write = nullptr; + + SECURITY_ATTRIBUTES sa_attr; + // Set the bInheritHandle flag so pipe handles are inherited. + sa_attr.nLength = sizeof(SECURITY_ATTRIBUTES); + sa_attr.bInheritHandle = TRUE; + sa_attr.lpSecurityDescriptor = nullptr; + + // Create the pipe for the child process's STDOUT. + if (!CreatePipe(&out_read, &out_write, &sa_attr, 0)) { + NOTREACHED() << "Failed to create pipe"; + return false; + } + + // Ensure we don't leak the handles. + base::win::ScopedHandle scoped_out_read(out_read); + base::win::ScopedHandle scoped_out_write(out_write); + + // Ensure the read handles to the pipes are not inherited. + if (!SetHandleInformation(out_read, HANDLE_FLAG_INHERIT, 0)) { + NOTREACHED() << "Failed to disabled pipe inheritance"; + return false; + } + + base::FilePath::StringType writable_command_line_string; + writable_command_line_string.assign(cl.data(), cl.size()); + + STARTUPINFO start_info = {}; + + start_info.cb = sizeof(STARTUPINFO); + start_info.hStdOutput = out_write; + // Keep the normal stdin/stderr. + start_info.hStdInput = GetStdHandle(STD_INPUT_HANDLE); + start_info.hStdError = GetStdHandle(STD_ERROR_HANDLE); + start_info.dwFlags |= STARTF_USESTDHANDLES; + + // Create the child process. + PROCESS_INFORMATION temp_process_info = {}; + if (!CreateProcess(nullptr, &writable_command_line_string[0], nullptr, + nullptr, + TRUE, // Handles are inherited. + 0, nullptr, nullptr, &start_info, &temp_process_info)) { + NOTREACHED() << "Failed to start process"; + return false; + } + + base::win::ScopedProcessInformation proc_info(temp_process_info); + + // Close our writing end of pipe now. Otherwise later read would not be able + // to detect end of child's output. + scoped_out_write.Close(); + + // Read output from the child process's pipe for STDOUT + const int kBufferSize = 1024; + char buffer[kBufferSize]; + + for (;;) { + DWORD bytes_read = 0; + BOOL success = + ::ReadFile(out_read, buffer, kBufferSize, &bytes_read, nullptr); + if (!success || bytes_read == 0) + break; + output->append(buffer, bytes_read); + } + + // Let's wait for the process to finish. + WaitForSingleObject(proc_info.process_handle(), INFINITE); + + int exit_code; + base::TerminationStatus status = + base::GetTerminationStatus(proc_info.process_handle(), &exit_code); + return status != base::TERMINATION_STATUS_PROCESS_CRASHED && + status != base::TERMINATION_STATUS_ABNORMAL_TERMINATION; +} + // Given the path to a batch file that runs Python, extracts the name of the // executable actually implementing Python. Generally people write a batch file // to put something named "python" on the path, which then just redirects to @@ -205,7 +283,7 @@ command.append(L"\" -c \"import sys; print sys.executable\"\""); std::string python_path; - if (base::GetAppOutput(command, &python_path)) { + if (GetAppOutput(command, &python_path)) { base::TrimWhitespaceASCII(python_path, base::TRIM_ALL, &python_path); // Python uses the system multibyte code page for sys.executable.