Skip to content

Commit 003e8f8

Browse files
committed
Don't use StaticString.utf8Start unless there is a pointer rep.
The docs for StaticString.utf8Start say it should runtime abort for this, so play it safe and handling when a StaticString doesn't have a ptr rep.
1 parent 57420fb commit 003e8f8

File tree

1 file changed

+29
-9
lines changed

1 file changed

+29
-9
lines changed

Sources/SwiftProtobuf/NameMap.swift

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,19 @@ fileprivate class InternPool {
5555
return immutable
5656
}
5757

58+
func intern(utf8Ptr: UnsafeBufferPointer<UInt8>) -> UnsafeRawBufferPointer {
59+
#if swift(>=4.1)
60+
let mutable = UnsafeMutableRawBufferPointer.allocate(byteCount: utf8Ptr.count,
61+
alignment: MemoryLayout<UInt8>.alignment)
62+
#else
63+
let mutable = UnsafeMutableRawBufferPointer.allocate(count: utf8.count)
64+
#endif
65+
mutable.copyBytes(from: utf8Ptr)
66+
let immutable = UnsafeRawBufferPointer(mutable)
67+
interned.append(immutable)
68+
return immutable
69+
}
70+
5871
deinit {
5972
for buff in interned {
6073
#if swift(>=4.1)
@@ -91,10 +104,17 @@ public struct _NameMap: ExpressibleByDictionaryLiteral {
91104
/// has to be computed, it caches the UTF-8 bytes in an
92105
/// unmovable and immutable heap area.
93106
internal struct Name: Hashable, CustomStringConvertible {
94-
// This is safe to use elsewhere in this library
95-
internal init(staticString: StaticString) {
107+
// This should not be used outside of this file, as it requires
108+
// coordinating the lifecycle with the lifecycle of the pool
109+
// where the raw UTF8 gets interned.
110+
fileprivate init(staticString: StaticString, pool: InternPool) {
96111
self.nameString = .staticString(staticString)
97-
self.utf8Buffer = UnsafeRawBufferPointer(start: staticString.utf8Start, count: staticString.utf8CodeUnitCount)
112+
if staticString.hasPointerRepresentation {
113+
self.utf8Buffer = UnsafeRawBufferPointer(start: staticString.utf8Start,
114+
count: staticString.utf8CodeUnitCount)
115+
} else {
116+
self.utf8Buffer = staticString.withUTF8Buffer { pool.intern(utf8Ptr: $0) }
117+
}
98118
}
99119

100120
// This should not be used outside of this file, as it requires
@@ -202,14 +222,14 @@ public struct _NameMap: ExpressibleByDictionaryLiteral {
202222
switch description {
203223

204224
case .same(proto: let p):
205-
let protoName = Name(staticString: p)
225+
let protoName = Name(staticString: p, pool: internPool)
206226
let names = Names(json: protoName, proto: protoName)
207227
numberToNameMap[number] = names
208228
protoToNumberMap[protoName] = number
209229
jsonToNumberMap[protoName] = number
210230

211231
case .standard(proto: let p):
212-
let protoName = Name(staticString: p)
232+
let protoName = Name(staticString: p, pool: internPool)
213233
let jsonString = toJsonFieldName(protoName.description)
214234
let jsonName = Name(string: jsonString, pool: internPool)
215235
let names = Names(json: jsonName, proto: protoName)
@@ -219,22 +239,22 @@ public struct _NameMap: ExpressibleByDictionaryLiteral {
219239
jsonToNumberMap[jsonName] = number
220240

221241
case .unique(proto: let p, json: let j):
222-
let jsonName = Name(staticString: j)
223-
let protoName = Name(staticString: p)
242+
let jsonName = Name(staticString: j, pool: internPool)
243+
let protoName = Name(staticString: p, pool: internPool)
224244
let names = Names(json: jsonName, proto: protoName)
225245
numberToNameMap[number] = names
226246
protoToNumberMap[protoName] = number
227247
jsonToNumberMap[protoName] = number
228248
jsonToNumberMap[jsonName] = number
229249

230250
case .aliased(proto: let p, aliases: let aliases):
231-
let protoName = Name(staticString: p)
251+
let protoName = Name(staticString: p, pool: internPool)
232252
let names = Names(json: protoName, proto: protoName)
233253
numberToNameMap[number] = names
234254
protoToNumberMap[protoName] = number
235255
jsonToNumberMap[protoName] = number
236256
for alias in aliases {
237-
let protoName = Name(staticString: alias)
257+
let protoName = Name(staticString: alias, pool: internPool)
238258
protoToNumberMap[protoName] = number
239259
jsonToNumberMap[protoName] = number
240260
}

0 commit comments

Comments
 (0)