Assembly.LoadFrom fails but only sporadically - .net-core

I want to write a program that watches a .dll for changes. When a change happens, it should load the assembly and invoke the foo function inside.
I have some code that should implement this, but it behaves strangely. Sometimes it works. Sometimes the assembly it loads will be an old version. Sometimes it will throw a BadImageFormatException exception.
Here is my program code (it is F# but I think this is a general .NET Core question):
module HotReloadDemo
open System
open System.IO
open System.Reflection
[<EntryPoint>]
let main argv =
let assemblyPath = argv.[0] // Path to the .dll to watch
let mutable lastWriteTime = DateTime.MinValue
while true do
let writeTime =
if File.Exists assemblyPath
then
File.GetLastWriteTimeUtc assemblyPath
else
lastWriteTime
if writeTime > lastWriteTime
then
lastWriteTime <- writeTime
try
printfn "Last write time: %O " lastWriteTime
printfn "Waiting for the build to finish (this is a hack)... "
Threading.Thread.Sleep 10000 // 10s is plenty long enough for the build to finish
printfn "Loading assembly path from: %s " assemblyPath
let assembly = Assembly.LoadFrom assemblyPath
printfn "Got assembly: %O" (assembly.GetName ())
let foo : (Unit -> int) option =
assembly.GetExportedTypes()
|> Array.tryHead
|> Option.bind (fun t -> t.GetMethod "foo" |> Option.ofObj)
|> Option.map (fun m -> (fun () -> m.Invoke (null, Array.empty) :?> int))
match foo with
| Some foo ->
printfn "foo () = %O" (foo ())
| None ->
printfn "foo not found"
with exn ->
printfn "%O" exn
else
()
Threading.Thread.Sleep 1000
0
I then have a very simple library to be watched in another project like this:
module HotReload
let foo () =
123456
To test it, I launch the "watcher" program. It successfully loads and invokes foo.
Then, I modify my library (e.g. to return a different number) and build it with dotnet build.
The watcher detects the change, loads the assembly again and invokes foo, but it prints the number from before the change!
Then, I modify the library again with a different number. It detects the change but crashes:
...
Loading assembly path from: ../hot-reload-lib/bin/Debug/netstandard2.0/hot-reload-lib.dll
System.BadImageFormatException: Could not load file or assembly '<Unknown>'. Index not found. (0x80131124)
File name: '<Unknown>'
at System.Runtime.Loader.AssemblyLoadContext.LoadFromPath(IntPtr ptrNativeAssemblyLoadContext, String ilPath, String niPath, ObjectHandleOnStack retAssembly)
at System.Runtime.Loader.AssemblyLoadContext.LoadFromAssemblyPath(String assemblyPath)
at System.Reflection.Assembly.LoadFrom(String assemblyFile)
...
What is going on here?
dotnet --version
3.0.100
lsb_release -a
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 18.04.3 LTS
Release: 18.04
Codename: bionic

Related

OCaml - Error: Module `Unix' is unavailable [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed last year.
Improve this question
I have been working through Harvard's CS51 class using materials available online. I'm trying to start the final project and downloaded the necessary files, but when I try to compile them I get the following error:
Error: Module `Unix' is unavailable (required by `Thread')
Command exited with code 2.
Compilation unsuccessful after building 18 targets (15 cached) in 00:00:00.
I have not made any changes to the code I downloaded yet and supposedly I should be able to compile it successfully in its current state. Any ideas why I might be getting this error?
EDIT: Below is the code from the file I downloaded and am trying to compile.
module Ev = Evaluation ;;
module MP = Miniml_parse ;;
module ML = Miniml_lex ;;
module Ex = Expr ;;
open Printf ;;
(* str_to_exp str -- Returns the expression specified by `str` using
the MiniML parser. *)
let str_to_exp (str: string) : Ex.expr =
let lexbuf = Lexing.from_string str in
let exp = MP.input ML.token lexbuf in
exp ;;
(* repl () -- Read-eval-print loop for MiniML, which prompts for and
evaluates MiniML expressions, printing the resulting value. Exits
the loop and terminates upon reading an end-of-file
(control-d). *)
let repl () =
(* lexical analyzer buffer from stdin *)
let lexbuf = Lexing.from_channel stdin in
(* set up the initial environment *)
let env = Ev.Env.empty () in
(* the main LOOP *)
while true do
(try
(* prompt *)
printf "<== %!";
(* READ and parse an expression from the input *)
let exp = MP.input ML.token lexbuf in
(* EVALuate it *)
let res = Ev.evaluate exp env in
(* PRINT the result; in this initial version, the trivial
evaluator just returns the expression unchanged as an
element of the `Env.value` type (found in `expr.ml`), so we
just extract the expression back out and print it *)
match res with
| Val resexp ->
printf "==> %s\n" (Ex.exp_to_abstract_string resexp)
| _ -> failwith "not handling other cases yet"
with
| MP.Error -> printf "xx> parse error\n"
| Ev.EvalError msg -> printf "xx> evaluation error: %s\n" msg
| Ev.EvalException -> printf "xx> evaluation exception\n"
| End_of_file -> printf "Goodbye.\n"; exit 0
);
flush stdout
done
;;
(* Run REPL if called from command line *)
try
let _ = Str.search_forward (Str.regexp "miniml\\.\\(byte\\|native\\|bc\\|exe\\)")
(Sys.argv.(0)) 0 in
repl ()
with Not_found -> () ;;
If I add open Unix it does take care of the error above, but I then get a different error:
26 | let lexbuf = Lexing.from_channel stdin in
^^^^^
Error: This expression has type Unix.file_descr
but an expression was expected of type in_channel
Command exited with code 2.
Generally, you have to explicitly ask to be linked to the Unix module.
The following program:
$ cat main.ml
Unix.gethostname () |> print_endline
would need to be built like this:
$ ocamlfind opt -linkpkg -package unix -o main main.ml; echo $?
0
whereas the bare minimum would fail with a similar error as yours:
$ ocamlopt -o main main.ml; echo $?
File "main.ml", line 1:
Error: No implementations provided for the following modules:
Unix referenced from main.cmx
2
That said, it looks like you're using Core, in which case (as well as most
other cases, actually) you're probably better off with dune:
$ cat dune
(executable
(name main)
(libraries unix))
$ dune build main.exe
$ ./_build/default/main.exe
amam-oy
However, if you ask Dune to link you to Core, Unix is already included
automatically, so the following dune file would also work for the above
program:
$ cat dune
(executable
(name main)
(libraries core))
Just add
open Unix;;
at the very start of your .ml file

Trying to use `NativePtr.toVoidPtr` or `NativeInt.ToPointer` causes `System.TypeLoadException`

So I was trying to do some OpenGl with silk.net and .net core 3.1. When I try to convert nativeptr<int> to voidptr I get weird error.
Below is minimal example to reproduce error.
#nowarn "9"
open FSharp.NativeInterop
[<EntryPoint>]
let main argv =
let numbers = [| 1..10 |]
use v = fixed numbers
let v' = NativePtr.toVoidPtr v
printfn "void = %A" v'
0 // return an integer exit code
This code when run generates:
$ dotnet run
Unhandled exception. System.TypeLoadException: The generic type 'Microsoft.FSharp.Core.FSharpFunc`2' was used with an invalid instantiation in assembly 'FSharp.Core, Version=4.7.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'.
at Program.main(String[] argv)
What am I doing wrong?

Issues with reading file in erlang

So, I am trying to read and write into a file.
While writing into the file, I need to check if a particular index exist in file then I don't write and throw error.
The data in file will look like this:
{1,{data,dcA,1}}.
{2, {data, dcA, 2}}.
{3,{data,dcA,3}}.
I added the dot at the end of each line because file:consult() needs the file like this.
Which is in this format.
{Index, {Data, Node, Index}}
When I have to add a new file, I check with this Index.
Here's what I have tried so far - https://pastebin.com/apnWLk45
And I run it like this:
193> {ok, P9} = poc:start(test1, self()).
{ok,<0.2863.0>}
194> poc:add(P9, Node, {6, data}).
In poc:add/3, P9 is the process id from the file:open.
I defined before in shell as dcA
And the third is the data - which is in this format - {Index, data}
Since I am using file:consult/1, it takes the filename as parameter. At that point, I only have process id. So I take the name from
file:pid2name(_Server).
This runs perfectly when I run it for the first time.
When I run this again - poc:add(P9, Node, {6, data2}), I get an error in this line file:pid2name(_Server).
exception error: no match of right hand side value undefined
How can I solve this issue?
I am new to Erlang. Just been a week that I started learning.
I am trying to read and write into a file. While writing into the
file, I need to check if a particular index exist in file then I don't
write and throw error.
A DETS table can easily do what you want:
-module(my).
-compile(export_all).
open_table() ->
dets:open_file(my_data, [{type, set}, {file, "./my_data.dets"}]).
close_table() ->
dets:close(my_data).
clear_table() ->
dets:delete_all_objects(my_data).
insert({Key, _Rest}=Data) ->
case dets:member(my_data, Key) of
true -> throw(index_already_exists);
false -> dets:insert(my_data, Data)
end.
all_items() ->
dets:match(my_data, '$1').
In the shell:
~/erlang_programs$ erl
Erlang/OTP 20 [erts-9.2] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:10] [hipe] [kernel-poll:false]
Eshell V9.2 (abort with ^G)
1> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> my:open_table().
{ok,my_data}
3> my:clear_table().
ok
4> my:all_items().
[]
5> my:insert({1, {data, a, b}}).
ok
6> my:insert({2, {data, c, d}}).
ok
7> my:insert({3, {data, e, f}}).
ok
8> my:all_items().
[[{1,{data,a,b}}],[{2,{data,c,d}}],[{3,{data,e,f}}]]
9> my:insert({1, {data, e, f}}).
** exception throw: index_already_exists
in function my:insert/1 (my.erl, line 15)
When I run this again - poc:add(P9, Node, {6, data2}), I get an error
in this line file:pid2name(_Server):
exception error: no match of right hand side value undefined
When a process opens a file, it becomes linked to a process that handles the file I/O, which means that if the process that opens the file terminates abnormally, the I/O process will also terminate. Here is an example:
-module(my).
-compile(export_all).
start() ->
{ok, Pid} = file:open('data.txt', [read, write]),
spawn(my, add, [Pid, x, y]),
exit("bye").
add(Pid, _X, _Y) ->
timer:sleep(1000), %Let start() process terminate.
{ok, Fname} = file:pid2name(Pid),
io:format("~s~n", [Fname]).
In the shell:
1> c(my).
my.erl:2: Warning: export_all flag enabled - all functions will be exported
{ok,my}
2> my:start().
** exception exit: "bye"
in function my:start/0 (my.erl, line 7)
3>
=ERROR REPORT==== 25-Jun-2018::13:28:48 ===
Error in process <0.72.0> with exit value:
{{badmatch,undefined},[{my,add,3,[{file,"my.erl"},{line,12}]}]}
According to the pid2name() docs:
pid2name(Pid) -> {ok, Filename} | undefined
the function can return undefined, which is what the error message is saying happened.

SBT Migration: How to replace Command.process

I have a statement in my 0.13x build.sbt file that composes a sbt.Command with the onLoad function:
onLoad in Global := (Command.process("project server", _: State)) compose (onLoad in Global).value
Now when updating to SBT 1.1.0 the Command.process method does not exist anymore, neither exists a method with the same signature. So how can I achieve the same effect?
Command.process was moved to MainLoop.processCommand
API reference - MainLoop.processCommand
You migrate to as below.
onLoad in Global := (MainLoop.processCommand(Exec("project server", None), _: State)) compose (onLoad in Global).value
onLoad in Global := (onLoad in Global).value andThen ("project server" :: _)
or if you fancy the even terser:
onLoad in Global ~= (_ andThen ("project server" :: _))

Ejabberd: error in simple module to handle offline messages

I have an Ejabberd 17.01 installation where I need to push a notification in case a recipient is offline. This seems the be a common task and solutions using a customized Ejabberd module can be found everywhere. However, I just don't get it running. First, here's me script:
-module(mod_offline_push).
-behaviour(gen_mod).
-export([start/2, stop/1]).
-export([push_message/3]).
-include("ejabberd.hrl").
-include("logger.hrl").
-include("jlib.hrl").
start(Host, _Opts) ->
?INFO_MSG("mod_offline_push loading", []),
ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, push_message, 10),
ok.
stop(Host) ->
?INFO_MSG("mod_offline_push stopping", []),
ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, push_message, 10),
ok.
push_message(From, To, Packet) ->
?INFO_MSG("mod_offline_push -> push_message", [To]),
Type = fxml:get_tag_attr_s(<<"type">>, Packet), % Supposedly since 16.04
%Type = xml:get_tag_attr_s(<<"type">>, Packet), % Supposedly since 13.XX
%Type = xml:get_tag_attr_s("type", Packet),
%Type = xml:get_tag_attr_s(list_to_binary("type"), Packet),
?INFO_MSG("mod_offline_push -> push_message", []),
ok.
The problem is the line Type = ... line in method push_message; without that line the last info message is logged (so the hook definitely works). When browsing online, I can find all kinds of function calls to extract elements from Packet. As far as I understand it changed over time with new releases. But it's not good, all variants lead in some kind of error. The current way returns:
2017-01-25 20:38:08.701 [error] <0.21678.0>#ejabberd_hooks:run1:332 {function_clause,[{fxml,get_tag_attr_s,[<<"type">>,{message,<<>>,normal,<<>>,{jid,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>},{jid,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>},[],[{text,<<>>,<<"sfsdfsdf">>}],undefined,[],#{}}],[{file,"src/fxml.erl"},{line,169}]},{mod_offline_push,push_message,3,[{file,"mod_offline_push.erl"},{line,33}]},{ejabberd_hooks,safe_apply,3,[{file,"src/ejabberd_hooks.erl"},{line,382}]},{ejabberd_hooks,run1,3,[{file,"src/ejabberd_hooks.erl"},{line,329}]},{ejabberd_sm,route,3,[{file,"src/ejabberd_sm.erl"},{line,126}]},{ejabberd_local,route,3,[{file,"src/ejabberd_local.erl"},{line,110}]},{ejabberd_router,route,3,[{file,"src/ejabberd_router.erl"},{line,87}]},{ejabberd_c2s,check_privacy_route,5,[{file,"src/ejabberd_c2s.erl"},{line,1886}]}]}
running hook: {offline_message_hook,[{jid,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>},{jid,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>},{message,<<>>,normal,<<>>,{jid,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>},{jid,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>},[],[{text,<<>>,<<"sfsdfsdf">>}],undefined,[],#{}}]}
I'm new Ejabberd and Erlang, so I cannot really interpret the error, but the Line 33 as mentioned in {mod_offline_push,push_message,3,[{file,"mod_offline_push.erl"}, {line,33}]} is definitely the line calling get_tag_attr_s.
UPDATE 2017/01/27: Since this cost me a lot of headache -- and I'm still not perfectly happy -- I post here my current working module in the hopes it might help others. My setup is Ejabberd 17.01 running on Ubuntu 16.04. Most stuff I tried and failed with seem to for older versions of Ejabberd:
-module(mod_fcm_fork).
-behaviour(gen_mod).
%% public methods for this module
-export([start/2, stop/1]).
-export([push_notification/3]).
%% included for writing to ejabberd log file
-include("ejabberd.hrl").
-include("logger.hrl").
-include("xmpp_codec.hrl").
%% Copied this record definition from jlib.hrl
%% Including "xmpp_codec.hrl" and "jlib.hrl" resulted in errors ("XYZ already defined")
-record(jid, {user = <<"">> :: binary(),
server = <<"">> :: binary(),
resource = <<"">> :: binary(),
luser = <<"">> :: binary(),
lserver = <<"">> :: binary(),
lresource = <<"">> :: binary()}).
start(Host, _Opts) ->
?INFO_MSG("mod_fcm_fork loading", []),
% Providing the most basic API to the clients and servers that are part of the Inets application
inets:start(),
% Add hook to handle message to user who are offline
ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, push_notification, 10),
ok.
stop(Host) ->
?INFO_MSG("mod_fcm_fork stopping", []),
ejabberd_hooks:add(offline_message_hook, Host, ?MODULE, push_notification, 10),
ok.
push_notification(From, To, Packet) ->
% Generate JID of sender and receiver
FromJid = lists:concat([binary_to_list(From#jid.user), "#", binary_to_list(From#jid.server), "/", binary_to_list(From#jid.resource)]),
ToJid = lists:concat([binary_to_list(To#jid.user), "#", binary_to_list(To#jid.server), "/", binary_to_list(To#jid.resource)]),
% Get message body
MessageBody = Packet#message.body,
% Check of MessageBody is not empty
case MessageBody/=[] of
true ->
% Get first element (no idea when this list can have more elements)
[First | _ ] = MessageBody,
% Get message data and convert to string
MessageBodyText = binary_to_list(First#text.data),
send_post_request(FromJid, ToJid, MessageBodyText);
false ->
?INFO_MSG("mod_fcm_fork -> push_notification: MessageBody is empty",[])
end,
ok.
send_post_request(FromJid, ToJid, MessageBodyText) ->
%?INFO_MSG("mod_fcm_fork -> send_post_request -> MessageBodyText = ~p", [Demo]),
Method = post,
PostURL = gen_mod:get_module_opt(global, ?MODULE, post_url,fun(X) -> X end, all),
% Add data as query string. Not nice, query body would be preferable
% Problem: message body itself can be in a JSON string, and I couldn't figure out the correct encoding.
URL = lists:concat([binary_to_list(PostURL), "?", "fromjid=", FromJid,"&tojid=", ToJid,"&body=", edoc_lib:escape_uri(MessageBodyText)]),
Header = [],
ContentType = "application/json",
Body = [],
?INFO_MSG("mod_fcm_fork -> send_post_request -> URL = ~p", [URL]),
% ADD SSL CONFIG BELOW!
%HTTPOptions = [{ssl,[{versions, ['tlsv1.2']}]}],
HTTPOptions = [],
Options = [],
httpc:request(Method, {URL, Header, ContentType, Body}, HTTPOptions, Options),
ok.
Actually it fails with second arg Packet you pass to fxml:get_tag_attr_s in push_message function
{message,<<>>,normal,<<>>,
{jid,<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>,
<<"homer">>,<<"xxx.xxx.xxx.xxx">>,<<"conference">>},
{jid,<<"carl">>,<<"xxx.xxx.xxx.xxx">>,<<>>,<<"carl">>,
<<"xxx.xxx.xxx.xxx">>,<<>>},
[],
[{text,<<>>,<<"sfsdfsdf">>}],
undefined,[],#{}}
because it is not xmlel
Looks like it is record "message" defined in tools/xmpp_codec.hrl
with <<>> id and type 'normal'
xmpp_codec.hrl
-record(message, {id :: binary(),
type = normal :: 'chat' | 'error' | 'groupchat' | 'headline' | 'normal',
lang :: binary(),
from :: any(),
to :: any(),
subject = [] :: [#text{}],
body = [] :: [#text{}],
thread :: binary(),
error :: #error{},
sub_els = [] :: [any()]}).
Include this file and use just
Type = Packet#message.type
or, if you expect binary value
Type = erlang:atom_to_binary(Packet#message.type, utf8)
The newest way to do that seems to be with xmpp:get_type/1:
Type = xmpp:get_type(Packet),
It returns an atom, in this case normal.

Resources