ZeroMQ消息的Swift便利初始化程序崩溃编译器

时间:2017-05-16 19:01:44

标签: swift3 zeromq

我在Docker容器中使用Swift 3和ZeroMQ,我想通过扩展程序向ZeroMQ.Message添加几个便利初始化程序。我目前所拥有的是崩溃编译器:

import Foundation
import ZeroMQ
import SwiftProtobuf

extension ZeroMQ.Message {
    convenience init?(string: String, encoding: String.Encoding = .utf8) {
        var asData = string.data(using:encoding)!

        asData.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) in
            let unsafe = UnsafeMutableRawPointer.allocate(bytes: asData.count, alignedTo: 8)
            unsafe.copyBytes(from: bytes, count: asData.count)
            try? self.init(data: unsafe, size: asData.count)
        }
    }

    convenience init?(protobuf: SwiftProtobuf.Message) {
        guard let data = try? protobuf.serializedData() else {
            return nil
        }

        data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) in
            let unsafe = UnsafeMutableRawPointer.allocate(bytes: data.count, alignedTo: 8)
            unsafe.copyBytes(from: bytes, count: data.count)
            try? self.init(data: unsafe, size: data.count)
        }
    }
}

我意识到我做错事的可能性非常高,因为这是一个非常严重的情况,并且#34;在高端&#34;。

编译器错误是(为了便于阅读,有一些手动换行):

Compile Swift Module 'src' (3 sources)
swift: /home/buildnode/disk2/workspace/oss-swift-3.1-package-linux-ubuntu-16_04/swift/
   ... lib/SILGen/ManagedValue.h:202:
   ... swift::SILValue swift::Lowering::ManagedValue::getLValueAddress() const:
Assertion `isLValue() && "This isn't an lvalue"' failed.

0  swift           0x000000000362f718
1  swift           0x000000000362fe56
2  libpthread.so.0 0x00007fd55e321390
3  libc.so.6       0x00007fd55cc87428 gsignal + 56
4  libc.so.6       0x00007fd55cc8902a abort + 362
5  libc.so.6       0x00007fd55cc7fbd7
6  libc.so.6       0x00007fd55cc7fc82
7  swift           0x0000000000b5fbfc
8  swift           0x0000000000b55ccc
9  swift           0x0000000000b9c0bd
10 swift           0x0000000000b9be2e
11 swift           0x0000000000b6af32
12 swift           0x0000000000b1f8f2
13 swift           0x0000000000b61607
14 swift           0x0000000000b572ab
15 swift           0x0000000000b5579c
16 swift           0x0000000000b5d73a
17 swift           0x0000000000b5921a
18 swift           0x0000000000b51c94
19 swift           0x0000000000bc95eb
20 swift           0x0000000000bc4cb1
21 swift           0x0000000000bc4018
22 swift           0x0000000000baea2d
23 swift           0x0000000000bacefd
24 swift           0x0000000000b57284
25 swift           0x0000000000b55ccc
26 swift           0x0000000000b9c0bd
27 swift           0x0000000000b9be2e
28 swift           0x0000000000b3720f
29 swift           0x0000000000b26dba
30 swift           0x0000000000b1f099
31 swift           0x0000000000ba28d8
32 swift           0x0000000000ba180b
33 swift           0x0000000000ba17ce
34 swift           0x0000000000b23dcb
35 swift           0x0000000000b24dbb
36 swift           0x0000000000b25415
37 swift           0x000000000047f43d
38 swift           0x000000000043b277
39 libc.so.6       0x00007fd55cc72830 __libc_start_main + 240
40 swift           0x00000000004386b9
Stack dump:
0.  Program arguments: /usr/bin/swift -frontend ...
1.  While silgen constructor initializer SIL function @_TFE3srcC6ZeroMQ7MessagecfT6stringSS8encodingVE10FoundationSS8Encoding_GSqS1__
    for 'init' at /app/Simple/Sources/extensions.swift:24:17
2.  While silgen closureexpr SIL function @_TFFE3srcC6ZeroMQ7MessagecFT6stringSS8encodingVE10FoundationSS8Encoding_GSqS1__U_FGSPVs5UInt8_T_
    for expression at [/app/Simple/Sources/extensions.swift:27:33 - line:31:9]
    RangeText="{ (bytes: UnsafePointer<UInt8>) in
            let unsafe = UnsafeMutableRawPointer.allocate(bytes: asData.count, alignedTo: 8)
            unsafe.copyBytes(from: bytes, count: asData!.count)
            try? self.init(data: unsafe, size: asData!.count)
        }"
<unknown>:0: error: unable to execute command: Aborted

类似的代码,但遵循工厂方法模式是好的,所以我认为问题在于使用try?和调用指定的初始化程序。

修改self.init(...)拉出尾随闭包的另一种方法:

convenience init?(string: String, encoding: String.Encoding = .utf8) {
    guard let data = string.data(using:encoding) else {
        return nil
    }

    let unsafe = UnsafeMutableRawPointer.allocate(bytes: data.count, alignedTo: 8)

    data.withUnsafeBytes { (bytes: UnsafePointer<UInt8>) in
        unsafe.copyBytes(from: bytes, count: data.count)
    }
    do {
        try self.init(data: unsafe, size: data.count)
    } catch {
        unsafe.deallocate(bytes: data.count, alignedTo: 8)
    }
}

以上产生的错误我不明白:

extensions.swift:41:17: error: 'self' used inside 'catch' block reachable from self.init call
    convenience init?(string: String, encoding: String.Encoding = .utf8) {

用单行替换do { ... } catch { ... }满足编译器,但在初始化程序抛出的情况下泄漏缓冲区(ZeroMQ在成功的情况下获取内存的所有权):

try? self.init(data: unsafe, size: data.count)

1 个答案:

答案 0 :(得分:0)

事实证明,我对ZeroMQ API的不熟悉意味着我走错了路,不必要地过度复杂化。 ZeroMQ已经有一个封装id: 12 intervalo: 138 active: 131 local: [Local_test] tipo: [Tipo_test] id: 21 intervalo: 218 active: 213 local: [Local_test_2] tipo: [Second_tipo_test] 方面的方法:

12;138;131;Local_test                    ;Tipo_test                    
21;218;213;Local_test_2                  ;Second_tipo_test             

...所以我需要做的就是为了实现增加发送Protobufs的便利性的目标,就是将简单的扩展方法添加到ZeroMQ的unsafeMutableBytes

public func send(_ data: Data, mode: SendMode = []) throws -> Bool