-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Stdlib] Fix entry-point-based process args #3108
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,69 +12,43 @@ | |
|
||
import SwiftShims | ||
|
||
internal class _Box<Wrapped> { | ||
internal var _value: Wrapped | ||
internal init(_ value: Wrapped) { self._value = value } | ||
} | ||
|
||
/// Command-line arguments for the current process. | ||
public enum Process { | ||
/// Return an array of string containing the list of command-line arguments | ||
/// with which the current process was invoked. | ||
internal static func _computeArguments() -> [String] { | ||
var result: [String] = [] | ||
let argv = unsafeArgv | ||
for i in 0..<Int(argc) { | ||
let arg = argv[i]! | ||
let converted = String(cString: arg) | ||
result.append(converted) | ||
} | ||
return result | ||
} | ||
|
||
/// The backing static variable for argument count may come either from the | ||
/// entry point or it may need to be computed e.g. if we're in the REPL. | ||
@_versioned | ||
internal static var _argc: Int32 = Int32() | ||
|
||
/// The backing static variable for arguments may come either from the | ||
/// entry point or it may need to be computed e.g. if we're in the REPL. | ||
/// | ||
/// Care must be taken to ensure that `_swift_stdlib_getUnsafeArgvArgc` is | ||
/// not invoked more times than is necessary (at most once). | ||
@_versioned | ||
internal static var _unsafeArgv: | ||
UnsafeMutablePointer<UnsafeMutablePointer<Int8>?>? | ||
= nil | ||
UnsafeMutablePointer<UnsafeMutablePointer<Int8>?> | ||
= _swift_stdlib_getUnsafeArgvArgc(&_argc) | ||
|
||
/// Access to the raw argc value from C. | ||
public static var argc: Int32 { | ||
_ = Process.unsafeArgv // Force evaluation of argv. | ||
return _argc | ||
} | ||
|
||
/// Access to the raw argv value from C. Accessing the argument vector | ||
/// through this pointer is unsafe. | ||
public static var unsafeArgv: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you can even flatten this indirection, and just have |
||
UnsafeMutablePointer<UnsafeMutablePointer<Int8>?> { | ||
return _unsafeArgv! | ||
return _unsafeArgv | ||
} | ||
|
||
/// Access to the swift arguments, also use lazy initialization of static | ||
/// properties to safely initialize the swift arguments. | ||
/// | ||
/// NOTE: we can not use static lazy let initializer as they can be moved | ||
/// around by the optimizer which will break the data dependence on argc | ||
/// and argv. | ||
public static var arguments: [String] { | ||
let argumentsPtr = UnsafeMutablePointer<AnyObject?>( | ||
Builtin.addressof(&_swift_stdlib_ProcessArguments)) | ||
|
||
// Check whether argument has been initialized. | ||
if let arguments = _stdlib_atomicLoadARCRef(object: argumentsPtr) { | ||
return (arguments as! _Box<[String]>)._value | ||
} | ||
|
||
let arguments = _Box<[String]>(_computeArguments()) | ||
_stdlib_atomicInitializeARCRef(object: argumentsPtr, desired: arguments) | ||
|
||
return arguments._value | ||
} | ||
public static var arguments: [String] | ||
= (0..<Int(argc)).map { String(cString: _unsafeArgv[$0]!) } | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should probably use |
||
} | ||
|
||
/// Intrinsic entry point invoked on entry to a standalone program's "main". | ||
// FIXME(ABI): Remove this and the entrypoints in SILGen. | ||
@_transparent | ||
public // COMPILER_INTRINSIC | ||
func _stdlib_didEnterMain( | ||
|
@@ -85,3 +59,10 @@ func _stdlib_didEnterMain( | |
Process._argc = Int32(argc) | ||
Process._unsafeArgv = argv | ||
} | ||
|
||
// FIXME: Move this to HashedCollections.swift.gyb | ||
internal class _Box<Wrapped> { | ||
internal var _value: Wrapped | ||
internal init(_ value: Wrapped) { self._value = value } | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
//===--- CommandLine.cpp - OS-specific command line arguments -------------===// | ||
// | ||
// This source file is part of the Swift.org open source project | ||
// | ||
// Copyright (c) 2016 Apple Inc. and the Swift project authors | ||
// Licensed under Apache License v2.0 with Runtime Library Exception | ||
// | ||
// See http://swift.org/LICENSE.txt for license information | ||
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// OS-specific command line argument handling is defined here. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include <vector> | ||
#include <string> | ||
#include <cassert> | ||
#include <climits> | ||
#include <cstdarg> | ||
#include <cstdint> | ||
#include <cstdio> | ||
#include <cstdlib> | ||
#include <cstring> | ||
|
||
#include "swift/Runtime/Debug.h" | ||
|
||
#include "../SwiftShims/RuntimeStubs.h" | ||
#include "../SwiftShims/GlobalObjects.h" | ||
|
||
// Backing storage for overrides of `Swift.Process.arguments`. | ||
static char **_swift_stdlib_ProcessOverrideUnsafeArgv = nullptr; | ||
static int _swift_stdlib_ProcessOverrideUnsafeArgc = 0; | ||
|
||
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE | ||
extern "C" void _swift_stdlib_overrideUnsafeArgvArgc(char **argv, int argc) { | ||
_swift_stdlib_ProcessOverrideUnsafeArgv = argv; | ||
_swift_stdlib_ProcessOverrideUnsafeArgc = argc; | ||
} | ||
|
||
#if defined(__APPLE__) | ||
// NOTE: forward declare this rather than including crt_externs.h as not all | ||
// SDKs provide it | ||
extern "C" char ***_NSGetArgv(void); | ||
extern "C" int *_NSGetArgc(void); | ||
|
||
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE | ||
extern "C" char ** _swift_stdlib_getUnsafeArgvArgc(int *outArgLen) { | ||
assert(outArgLen != nullptr); | ||
|
||
if (_swift_stdlib_ProcessOverrideUnsafeArgv) { | ||
*outArgLen = _swift_stdlib_ProcessOverrideUnsafeArgc; | ||
return _swift_stdlib_ProcessOverrideUnsafeArgv; | ||
} | ||
|
||
*outArgLen = *_NSGetArgc(); | ||
return *_NSGetArgv(); | ||
} | ||
#elif defined(__linux__) || defined(__CYGWIN__) || defined(__FreeBSD__) | ||
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE | ||
extern "C" char ** _swift_stdlib_getUnsafeArgvArgc(int *outArgLen) { | ||
assert(outArgLen != nullptr); | ||
|
||
if (_swift_stdlib_ProcessOverrideUnsafeArgv) { | ||
*outArgLen = _swift_stdlib_ProcessOverrideUnsafeArgc; | ||
return _swift_stdlib_ProcessOverrideUnsafeArgv; | ||
} | ||
|
||
FILE *cmdline = fopen("/proc/self/cmdline", "rb"); | ||
if (!cmdline) { | ||
swift::fatalError(0, | ||
"fatal error: Unable to open interface to '/proc/self/cmdline'.\n"); | ||
} | ||
char *arg = nullptr; | ||
size_t size = 0; | ||
std::vector<char *> argvec; | ||
while (getdelim(&arg, &size, 0, cmdline) != -1) { | ||
argvec.push_back(strdup(arg)); | ||
} | ||
if (arg) { | ||
free(arg); | ||
} | ||
fclose(cmdline); | ||
*outArgLen = argvec.size(); | ||
char **outBuf = (char **)calloc(argvec.size() + 1, sizeof(char *)); | ||
std::copy(argvec.begin(), argvec.end(), outBuf); | ||
outBuf[argvec.size()] = nullptr; | ||
|
||
return outBuf; | ||
} | ||
#elif defined (_MSC_VER) | ||
extern int *__argc; | ||
extern char **__argv; | ||
|
||
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE | ||
extern "C" char ** _swift_stdlib_getUnsafeArgvArgc(int *outArgLen) { | ||
assert(outArgLen != nullptr); | ||
|
||
if (_swift_stdlib_ProcessOverrideUnsafeArgv) { | ||
*outArgLen = _swift_stdlib_ProcessOverrideUnsafeArgc; | ||
return _swift_stdlib_ProcessOverrideUnsafeArgv; | ||
} | ||
|
||
*outArgLen = __argc; | ||
return __argv; | ||
} | ||
#else // __ANDROID__; Add your favorite arch's command line arg grabber here. | ||
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_INTERFACE | ||
extern "C" char ** _swift_stdlib_getUnsafeArgvArgc(int *outArgLen) { | ||
if (_swift_stdlib_ProcessOverrideUnsafeArgv) { | ||
*outArgLen = _swift_stdlib_ProcessOverrideUnsafeArgc; | ||
return _swift_stdlib_ProcessOverrideUnsafeArgv; | ||
} | ||
|
||
swift::fatalError(0, | ||
"fatal error: Command line arguments not supported on this platform.\n"); | ||
} | ||
#endif | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
#include "ProcessStressTest.h" | ||
|
||
int main(int argc, char **argv) { | ||
swift_process_test_getProcessArgs(); | ||
return 0; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
// Declared in ProcessStressTest.swift. | ||
extern void swift_process_test_getProcessArgs(void); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nitpick: please make this a proper doc comment, so that it shows up in Quick Help.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll get it when I remove the compiler intrinsic.