From ee9fcf901b975b4f5c53dd9d0fca2b4faef2a314 Mon Sep 17 00:00:00 2001 From: Yatao Li Date: Thu, 19 Nov 2020 11:58:55 +0800 Subject: [PATCH] fix msgpack deserialization... why? --- Program.fs | 9 +++------ Properties/launchSettings.json | 3 +-- common.fs | 2 +- model.fs | 6 +++++- neovim.fs | 23 +++++++++++++++-------- states.fs | 3 +++ 6 files changed, 28 insertions(+), 18 deletions(-) diff --git a/Program.fs b/Program.fs index 7e32652..31b4c81 100644 --- a/Program.fs +++ b/Program.fs @@ -37,13 +37,10 @@ type MsgPackFormatter(resolver: IFormatterResolver) = member x.Deserialize(bytes: byte[] , offset: int, formatterResolver: IFormatterResolver , readSize: byref) = if MessagePackBinary.GetMessagePackType(bytes, offset) = MessagePackType.Extension then let result = MessagePackBinary.ReadExtensionFormat(bytes, offset, &readSize) - if result.TypeCode = 1y then - let mutable _size = 0 - m_formatter.Deserialize(result.Data, 0, formatterResolver, &_size) - else - m_formatter.Deserialize(bytes, offset, formatterResolver, &readSize) + let mutable _size = 0 + m_formatter.Deserialize(result.Data, 0, formatterResolver, &_size) else - m_formatter.Deserialize(bytes, offset, formatterResolver, &readSize) + m_formatter.Deserialize(bytes, offset, formatterResolver, &readSize) type MsgPackResolver() = static let s_formatter = box(MsgPackFormatter(MessagePack.Resolvers.StandardResolver.Instance)) diff --git a/Properties/launchSettings.json b/Properties/launchSettings.json index b14f62c..a09ae13 100644 --- a/Properties/launchSettings.json +++ b/Properties/launchSettings.json @@ -1,8 +1,7 @@ { "profiles": { "fvim": { - "commandName": "Project", - "commandLineArgs": "--daemon" + "commandName": "Project" }, "norc": { "commandName": "Project", diff --git a/common.fs b/common.fs index d2120e3..40e3138 100644 --- a/common.fs +++ b/common.fs @@ -162,7 +162,7 @@ let newProcess prog args stderrenc = p.EnableRaisingEvents <- true // in case the parent crashed and we happen to be running Windows(tm)... // TODO need further investigation. - ignore <| AppDomain.CurrentDomain.ProcessExit.Subscribe(fun _ -> p.Kill(true)) + ignore <| AppDomain.CurrentDomain.ProcessExit.Subscribe(fun _ -> try p.Kill(true) with _ -> ()) p [] diff --git a/model.fs b/model.fs index c590aa2..9c099f9 100644 --- a/model.fs +++ b/model.fs @@ -527,6 +527,8 @@ let Start (serveropts, norc, debugMultigrid) = trace "commencing early initialization..." async { + do! Async.SwitchToNewThread() + let! api_info = Async.AwaitTask(nvim.call { method = "nvim_get_api_info"; parameters = [||] }) let api_query_result = match api_info.result with @@ -663,7 +665,9 @@ let Start (serveropts, norc, debugMultigrid) = if not norc then let! _ = Async.AwaitTask(nvim.command "if v:vim_did_enter | runtime! ginit.vim | else | execute \"autocmd VimEnter * runtime! ginit.vim\" | endif") () - } |> Async.RunSynchronously + } + |> Async.Start + |> ignore let Flush = ev_flush.Publish diff --git a/neovim.fs b/neovim.fs index fdca422..1d5c241 100644 --- a/neovim.fs +++ b/neovim.fs @@ -90,6 +90,8 @@ type Nvim() = if id < 0 then proc.Kill() failwithf "Remote daemon closed the connection with error code %d" id + else + trace "Connected to session %d" id TunneledSession proc member this.start opts = @@ -129,28 +131,33 @@ type Nvim() = let read (ob: IObserver) (cancel: CancellationToken) = Task.Factory.StartNew(fun () -> trace "begin read loop" - let mutable ex = false - while not ex && not cancel.IsCancellationRequested do + let mutable channelClosed = false + let mutable unhandledException = None + while not channelClosed && not cancel.IsCancellationRequested && unhandledException.IsNone do try let data = MessagePackSerializer.Deserialize(stdout, true) ob.OnNext(data) with - | :? InvalidOperationException + | :? InvalidOperationException as _ex when _ex.Message = "Invalid MessagePack code was detected, code:-1" + -> channelClosed <- true | :? System.IO.IOException | :? System.Net.Sockets.SocketException | :? ObjectDisposedException - as _ex -> ex <- true + -> channelClosed <- true + | ex -> unhandledException <- Some ex - let ec = serverExitCode() - if ec.IsSome then - let code = ec.Value + match serverExitCode(), unhandledException with + | Some code, _ -> trace "end read loop: process exited, code = %d" code if code <> 0 then m_cancelSrc.Cancel() ob.OnNext([|box (Crash code)|]) else ob.OnNext([|box Exit|]) - else + | _, Some ex -> + trace "end read loop: unhandled exception." + ob.OnNext([|box (UnhandledException ex)|]) + | _ -> trace "end read loop." ob.OnNext([|box Exit|]) ob.OnCompleted() diff --git a/states.fs b/states.fs index 3953948..4a35108 100644 --- a/states.fs +++ b/states.fs @@ -31,6 +31,7 @@ type Event = | Notification of nreq: Request | Error of emsg: string | Crash of ccode: int32 +| UnhandledException of ex: exn | Exit let private _stateChangeEvent = Event() @@ -278,6 +279,8 @@ let msg_dispatch = trace "rpc" "neovim crashed with code %d" code _crashcode <- code failwithf "neovim crashed" + | UnhandledException ex -> + raise ex | other -> trace "rpc" "unrecognized event: %A" other