go 有办法调用基础库 golang.org/x/crypto 的私有结构和方法吗?
开源项目 github.com/trzsz/trzsz-ssh 想支持 ssh ControlMaster 的功能。
go 基础库 golang.org/x/crypto 有个 PR go-review.googlesource.com/c/crypto/+/383374 还没合入。
有办法在不 fork 基础库 golang.org/x/crypto 的情况下,优雅地在自己的项目实现这个 PR 的逻辑吗?
import "golang.org/x/crypto/ssh"
func NewControlClientConn(c net.Conn) (ssh.Conn, <-chan ssh.NewChannel, <-chan *ssh.Request, error) {
conn := &ssh.connection{ ■ undefined: ssh.connection
sshConn: ssh.sshConn{conn: c}, ■ undefined: ssh.sshConn
}
var err error
if conn.transport, err = handshakeControlProxy(c); err != nil {
return nil, nil, nil, fmt.Errorf("ssh: control proxy handshake failed; %v", err)
}
conn.mux = ssh.newMux(conn.transport) ■ undefined: ssh.newMux
return conn, conn.mux.incomingChannels, conn.mux.incomingRequests, nil
}
handshakeControlProxy 这个函数很好办,直接从 PR 中复制出来就行了。
问题:上面的 ssh.connection、ssh.sshConn 和 ssh.newMux 依赖很深,发现很难直接 copy 出来。
用 go:linkname 把私有函数链出来; unsafe 读写私有结构
unsafe 能引用私有结构吗?具体怎么做?
chatGPT ?
你问问看?
V2EX 不允许 gpt 回答的,会 ban 账号的。
可以看 github.com/dolthub/maphash 这玩意的实现,其实就是自己整个和私有结构体一模一样的,然后把指针映射到自己的结构体上
#1 link 要在 golang.org/x/crypto 里面写其实可以用 go 汇编,可以直接根据包名﹒变量名引用(这个不安全)
不需要的,外面写一个相同定义的函数 link 原函数就行了//go:linkname func1 pkg.func1func func1(a string) string记得 import _ "unsafe"
现在要调用的函数是func newMux(p packetConn) mux问题是 packetConn 和 mux 都是私有的,怎么用 go:linkname 定义呢?type packetConn interface { // Encrypt and send a packet of data to the remote peer. writePacket(packet []byte) error // Read a packet from the connection. The read is blocking, // i.e. if error is nil, then the returned byte slice is // always non-empty. readPacket() ([]byte, error) // Close closes the write-side of the connection. Close() error}type mux struct { conn packetConn chanList chanList incomingChannels chan NewChannel globalSentMu sync.Mutex globalResponses chan interface{} incomingRequests chan Request errCond *sync.Cond err error}
#8 你这反了,你看 runtime now github.com/golang/go/blob/master/src/runtime/timestub.go#L14连接到 time now ,linkname 是写在 runtime 而不是 time
最好别拿 linkname 搞,升级 go 版本的时候容易炸。还是乖乖开个 fork 吧
汇编可以参考这个 github.com/golang/go/blob/master/src/sync/atomic/asm.s#L10
fork golang.org/x/crypto 也不好啊。
Go 创始人说:最好的方法就是复制
#14 反对他。我只是要加一点点功能,我可没有能力和精力去维护那么大一个库。
可以算偏移量直接读写; 或者定义一个相同结构的 struct, unsafe 强转 (我不清楚是否安全)
#10 ,linkname 在哪边写都是可以的
可以复制, 毕竟标准库里为了解决循环引用 也搞了很多复制
用 unsafe.Pointer
+ 偏移量 可以做到
packetConn 是个 interface 吧,直接拷贝出来就是了,
mux ,骚一点就是。。//go:linkname newMux golang.org/x/crypto/ssh.newMuxfunc newMux(p packetConn) muxtype mux struct { conn packetConn _ [40]byte incomingChannels chan ssh.NewChannel globalSentMu sync.Mutex globalResponses chan interface{} incomingRequests chan ssh.Request errCond *sync.Cond err error}
接口可以//go:linkname SendRequest golang.org/x/crypto/ssh.(mux).SendRequestfunc SendRequest(mux mux, name string, wantReply bool, payload []byte) (bool, []byte, error)func (c *connection) SendRequest(name string, wantReply bool, payload []byte) (bool, []byte, error) { return SendRequest(c.mux, name, wantReply, payload)}不过整体也不是很优雅就是了,兼容性很差
我觉得最优雅的办法就是 fork 。fork 完 release 个新版本,等 ssh 真的支持你想要的,再发布个新版本换回原来的
但是这样 go 版本更新的时候你可以显式的 review 改了什么,用 linkname 炸的无声无息,stacktrace 都没有那种
【感谢 Todd投递本文 – 微博帐号:@weidagang 】 需求又变了,怎么办? 先上一个轻松的段子: 程序员XX遭遇车祸成植物人,医生说活下来的希望只有万分之一,唤醒更…
github.com/google/guava/wiki 看了 api ,觉得这是对 jdk 很好的补充,大家工作中用的多吗? 用的很多,很多库间接引用了这个包 事实是你…
字体变的歪歪扭扭的,只有文件代码里的字体是正确的。找不到在哪里改... 2023.6 版本的就是看着很舒服的字体。 还发现了一个改变,这个间隙变大了,不是默认靠左了😂![i…