Skip to content

Commit 044d8c9

Browse files
authored
Merge pull request #75378 from jckarter/warn-on-runtime-function-symbol-references
Stage in a warning when trying to access symbols used by the compiler.
2 parents 536a889 + 8bc5a1f commit 044d8c9

File tree

5 files changed

+113
-7
lines changed

5 files changed

+113
-7
lines changed

docs/ReferenceGuides/UnderscoredAttributes.md

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -465,6 +465,10 @@ Also similar to `@_silgen_name`, but a function declared with
465465
`@_extern(c)` is assumed to use the C ABI, while `@_silgen_name`
466466
assumes the Swift ABI.
467467

468+
It is always better to refer to C declarations by importing their
469+
native declarations from a header or module using Swift's C interop
470+
support when possible.
471+
468472
## `@_fixed_layout`
469473

470474
Same as `@frozen` but also works for classes.
@@ -1106,9 +1110,43 @@ Darwin) is maintained, unless "raw:" is used, in which case the name provided is
11061110
expected to already be mangled.
11071111

11081112
Since this has label-like behavior, it may not correspond to any declaration;
1109-
if so, it is assumed that the function/global is implemented in C.
1110-
1111-
A function defined by `@_silgen_name` is assumed to use the Swift ABI.
1113+
if so, it is assumed that the function/global is implemented possibly
1114+
in some other language; that implementation however is assumed to use
1115+
the Swift ABI as if it were defined in Swift.
1116+
1117+
There are very few legitimate uses for this attribute. There are many
1118+
ways to misuse it:
1119+
1120+
- Don't use `@_silgen_name` to access C functions, since those use the C ABI.
1121+
Import a header or C module to access C functions.
1122+
- Don't use `@_silgen_name` to export Swift functions to C/ObjC. `@_cdecl` or
1123+
`@objc` can do that.
1124+
- Don't use `@_silgen_name` to link to `swift_*` symbols from the Swift runtime.
1125+
Calls to these functions have special semantics to the compiler, and accessing
1126+
them directly will lead to unpredictable compiler crashes and undefined
1127+
behavior. Use language features, or if you must, the `Builtin` module, instead.
1128+
- Don't use `@_silgen_name` for dynamic linker discovery. Swift symbols cannot
1129+
be reliably recovered through C interfaces like `dlsym`. If you want to
1130+
implement a plugin-style interface, use `Bundle`/`NSBundle` if available, or
1131+
export your plugin entry points as C entry points using `@_cdecl`.
1132+
1133+
Legitimate uses may include:
1134+
1135+
- Use `@_silgen_name` if you're implementing the Swift runtime.
1136+
- Use `@_silgen_name` if you need to make a change to an ABI-stable
1137+
declaration's signature that would normally alter its mangled name, but you
1138+
need to preserve the old mangled name for ABI compatibility. You will need
1139+
to be careful that the change doesn't materially affect the actual calling
1140+
convention of the function in an incompatible way.
1141+
- Use `@_silgen_name` if certain declarations need to have predictable symbol
1142+
names, such as to be easily referenced by linker scripts or other highly
1143+
customized build environments (and it's OK for those predictable symbols to
1144+
reference functions with a Swift ABI).
1145+
- Use `@_silgen_name` to interface build products that must be linked
1146+
together but built completely separately, such that one can't import the other
1147+
normally. For this to work, the declaration(s) and definition must exactly
1148+
match, using the exact same definitions of any referenced types or other
1149+
declarations. The compiler can't help you if you mismatch.
11121150

11131151
For more details, see the
11141152
[Standard Library Programmer's Manual](https://github.com/swiftlang/swift/blob/main/docs/StandardLibraryProgrammersManual.md#_silgen_name).

include/swift/AST/DiagnosticsSema.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1957,6 +1957,12 @@ ERROR(section_linkage_markers_disabled,none,
19571957
ERROR(section_empty_name,none,
19581958
"@_section section name cannot be empty", ())
19591959

1960+
// @_silgen_name and friends
1961+
WARNING(reserved_runtime_symbol_name,none,
1962+
"symbol name '%0' is reserved for the Swift runtime and cannot be "
1963+
"directly referenced without causing unpredictable behavior; "
1964+
"this will become an error", (StringRef))
1965+
19601966
// @_extern
19611967
ERROR(attr_extern_experimental,none,
19621968
"@_extern requires '-enable-experimental-feature Extern'", ())

lib/Sema/TypeCheckAttr.cpp

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,6 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
144144
IGNORED_ATTR(NoObjCBridging)
145145
IGNORED_ATTR(EmitAssemblyVisionRemarks)
146146
IGNORED_ATTR(ShowInInterface)
147-
IGNORED_ATTR(SILGenName)
148147
IGNORED_ATTR(StaticInitializeObjCMetadata)
149148
IGNORED_ATTR(SynthesizedProtocol)
150149
IGNORED_ATTR(Testable)
@@ -364,6 +363,8 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
364363

365364
void visitStaticExclusiveOnlyAttr(StaticExclusiveOnlyAttr *attr);
366365
void visitWeakLinkedAttr(WeakLinkedAttr *attr);
366+
367+
void visitSILGenNameAttr(SILGenNameAttr *attr);
367368
};
368369

369370
} // end anonymous namespace
@@ -2223,6 +2224,30 @@ void AttributeChecker::visitAvailableAttr(AvailableAttr *attr) {
22232224
}
22242225
}
22252226

2227+
static bool canDeclareSymbolName(StringRef symbol, ModuleDecl *fromModule) {
2228+
// The Swift standard library needs to be able to define reserved symbols.
2229+
if (fromModule->isStdlibModule()
2230+
|| fromModule->getName() == fromModule->getASTContext().Id_Concurrency
2231+
|| fromModule->getName() == fromModule->getASTContext().Id_Distributed) {
2232+
return true;
2233+
}
2234+
2235+
// Swift runtime functions are a private contract between the compiler and
2236+
// runtime, and attempting to access them directly without going through
2237+
// builtins or proper language features breaks the compiler in various hard
2238+
// to predict ways. Warn when code attempts to do so; hopefully we can
2239+
// promote this to an error after a while.
2240+
2241+
return llvm::StringSwitch<bool>(symbol)
2242+
#define FUNCTION(_, Name, ...) \
2243+
.Case(#Name, false) \
2244+
.Case("_" #Name, false) \
2245+
.Case(#Name "_", false) \
2246+
.Case("_" #Name "_", false)
2247+
#include "swift/Runtime/RuntimeFunctions.def"
2248+
.Default(true);
2249+
}
2250+
22262251
void AttributeChecker::visitCDeclAttr(CDeclAttr *attr) {
22272252
// Only top-level func decls are currently supported.
22282253
if (D->getDeclContext()->isTypeContext())
@@ -2231,6 +2256,12 @@ void AttributeChecker::visitCDeclAttr(CDeclAttr *attr) {
22312256
// The name must not be empty.
22322257
if (attr->Name.empty())
22332258
diagnose(attr->getLocation(), diag::cdecl_empty_name);
2259+
2260+
// The standard library can use @_cdecl to implement runtime functions.
2261+
if (!canDeclareSymbolName(attr->Name, D->getModuleContext())) {
2262+
diagnose(attr->getLocation(), diag::reserved_runtime_symbol_name,
2263+
attr->Name);
2264+
}
22342265
}
22352266

22362267
void AttributeChecker::visitExposeAttr(ExposeAttr *attr) {
@@ -2338,12 +2369,14 @@ void AttributeChecker::visitExternAttr(ExternAttr *attr) {
23382369
diagnoseAndRemoveAttr(attr, diag::attr_extern_experimental);
23392370
return;
23402371
}
2372+
23412373
// Only top-level func or static func decls are currently supported.
23422374
auto *FD = dyn_cast<FuncDecl>(D);
23432375
if (!FD || (FD->getDeclContext()->isTypeContext() && !FD->isStatic())) {
23442376
diagnose(attr->getLocation(), diag::extern_not_at_top_level_func);
23452377
}
23462378

2379+
23472380
// C name must not be empty.
23482381
if (attr->getExternKind() == ExternKind::C) {
23492382
StringRef cName = attr->getCName(FD);
@@ -2358,6 +2391,14 @@ void AttributeChecker::visitExternAttr(ExternAttr *attr) {
23582391
diagnose(attr->getLocation(), diag::extern_c_maybe_invalid_name, cName)
23592392
.fixItInsert(attr->getRParenLoc(), (", \"" + cName + "\"").str());
23602393
}
2394+
2395+
// Diagnose reserved symbol names.
2396+
// The standard library can't use normal C interop so needs extern(c)
2397+
// for access to C standard library and ObjC/Swift runtime functions.
2398+
if (!canDeclareSymbolName(cName, D->getModuleContext())) {
2399+
diagnose(attr->getLocation(), diag::reserved_runtime_symbol_name,
2400+
cName);
2401+
}
23612402

23622403
// Ensure the decl has C compatible interface. Otherwise it produces diagnostics.
23632404
if (!isCCompatibleFuncDecl(FD)) {
@@ -2407,6 +2448,13 @@ static bool allowSymbolLinkageMarkers(ASTContext &ctx, Decl *D) {
24072448
return false;
24082449
}
24092450

2451+
void AttributeChecker::visitSILGenNameAttr(SILGenNameAttr *A) {
2452+
if (!canDeclareSymbolName(A->Name, D->getModuleContext())) {
2453+
diagnose(A->getLocation(), diag::reserved_runtime_symbol_name,
2454+
A->Name);
2455+
}
2456+
}
2457+
24102458
void AttributeChecker::visitUsedAttr(UsedAttr *attr) {
24112459
if (!allowSymbolLinkageMarkers(Ctx, D)) {
24122460
diagnoseAndRemoveAttr(attr, diag::section_linkage_markers_disabled);

test/Generics/slice_test.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,8 @@ func testslice(_ s: Array<Int>) {
3030
_ = s[..<2]
3131
}
3232

33-
@_silgen_name("malloc") func c_malloc(_ size: Int) -> UnsafeMutableRawPointer
34-
@_silgen_name("free") func c_free(_ p: UnsafeMutableRawPointer)
33+
@_silgen_name("c_malloc") func c_malloc(_ size: Int) -> UnsafeMutableRawPointer
34+
@_silgen_name("c_free") func c_free(_ p: UnsafeMutableRawPointer)
3535

3636
class Vector<T> {
3737
var length : Int

test/attr/attr_silgen_name.swift

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-typecheck-verify-swift
1+
// RUN: %target-typecheck-verify-swift -enable-experimental-feature Extern
22

33
@_silgen_name("foo") // expected-note {{attribute already specified here}}
44
@_silgen_name("bar") // expected-error {{duplicate attribute}}
@@ -14,3 +14,17 @@ func func_with_nested__silgen_name() {
1414
exit(0)
1515
}
1616

17+
// Ensure that magic runtime symbol names can't be declared or defined through
18+
// various symbol-assigning attributes
19+
20+
@_silgen_name("swift_retain") // expected-warning{{reserved}}
21+
func liveDangerously() {}
22+
23+
@_silgen_name("swift_retain") // expected-warning{{reserved}}
24+
func liveRecklessly();
25+
26+
@_extern(c, "swift_retain") // expected-warning{{reserved}}
27+
func liveEphemerally()
28+
29+
@_cdecl("swift_retain") // expected-warning{{reserved}}
30+
func liveFrivolously() {}

0 commit comments

Comments
 (0)