[HN Gopher] Rust panics under the hood, and implementing them in...
___________________________________________________________________
Rust panics under the hood, and implementing them in .NET
Author : todsacerdoti
Score : 125 points
Date : 2024-09-23 05:26 UTC (17 hours ago)
(HTM) web link (fractalfir.github.io)
(TXT) w3m dump (fractalfir.github.io)
| CharlieDigital wrote:
| From the repo[0]: > The project aims to provide
| a way to easily use Rust libraries in .NET. It comes with a
| Rust/.NET interop layer, which allows you to easily interact with
| .NET code from Rust
|
| Are there some standout Rust libraries out there? Very curious
| about the motivation and use cases.
|
| [0] https://github.com/FractalFir/rustc_codegen_clr
| jasonjayr wrote:
| .net considers the rust code "unsafe" so you can do unmanaged,
| non-GC stuff in the Rust portion of the code.
| CharlieDigital wrote:
| You can already do that from .NET itself.
|
| My question here is more along the lines of: "what Rust libs
| are out there that I might be interested in from .NET?"
| giancarlostoro wrote:
| What I think you missed in that statement is that the code
| is technically still Rust safe, so in theory it wouldn't
| just be unsafe .NET Code, it would be Rust safe code that
| happens to run on .NET with a speed up since its less
| managed. It's kind of genius, if I'm not misunderstanding.
| bangaladore wrote:
| If you go through the hassle of integrating this, you
| would be better off manually optimizing your C# code to
| reduce GC allocations, which you can do within the safe
| subset of C#. This is not targetted towards increasing
| performance as it seems the entirety of the rust
| application gets converted to IL, incurring large
| performance hits across the board.
|
| If you do not want JITing, you can already "pre-compile"
| dotnet code, and you will achieve near-native performance
| in either case--far better performance than running Rust
| as IL, as the author indicated.
|
| In my opinion, the use case for this is minuscule at
| best.
| jen20 wrote:
| One example is the core Temporal.io client, which is
| implemented in Rust, and wrapped by (most of) the other
| SDKs including .NET.
|
| I imagine this pattern will become more common for fat
| clients where it is desirable have a single implementation
| with idiomatic language bindings.
| kodablah wrote:
| Correct, granted it's more complicated than "clients". At
| least Node.js (Neon), Python (PyO3), and Ruby (rb-
| sys/magnus) have nice supported bridge wrappers. The
| .NET-to-Rust interfacing in the Temporal .NET SDK
| required pure C FFI and P/Invoke and being careful about
| GC and lifetimes during interop. Can see the bridge at
| https://github.com/temporalio/sdk-
| dotnet/tree/main/src/Tempo....
|
| I can say with regards to panics, .NET is very nice to
| wrap Rust panics into `SEHException` classes (though of
| course we strive to be completely panic free).
| xelamonster wrote:
| I honestly can't think of any drop-in libraries that would
| give you much .NET (wow that name sucks to type on mobile)
| doesn't already give you, though if you're struggling with
| a particularly slow implementation of something the Rust
| version is likely faster. I think the more useful case for
| Rust here is rewriting the heavier or more error-prone
| parts of your own app logic in it.
| radicalbyte wrote:
| Rust is a step back with respect to being error prone,
| unless you're doing manual memory management in .Net
| (i.e. unsafe).
|
| The use cases I see are going to be things such as
| sharing a library over multiple platforms. I've done that
| with Go in the past via cgo.
| phs2501 wrote:
| Rust is a step sideways if anything. Yeah, you don't have
| manual memory management headaches in .NET, but you also
| don't have Rust's fairly strong compile-time guarantees
| about memory sharing and thread safety.
|
| Which enables stuff like rayon where you can basically
| blindly replace map with parallel map and if it compiles,
| it _should_ be safe to run.
|
| (I'm not super familiar with the .NET ecosystem, so it's
| quite possible there's equivalent tooling for enforced
| thread safety. I haven't heard much about it though, if
| so.)
| neonsunset wrote:
| FWIW .NET has many alternatives to popular Rust packages.
| Features provided by Rayon come out of box - it's your
| Parallel.For/Each/Async and arr.AsParallel().Select(...),
| etc. Their cost is going to be different, but I
| consistently find TPL providing pretty fool-proof
| underlying heuristics to make sure even and optimal load
| distrbituion. Rayon is likely going to be cheaper on
| fine-grained work items, but for coarse grained ones
| there will be little to no difference.
|
| I think the main advantages of Rust are its heavier
| reliance on static dispatch when e.g. writing iterator
| expressions (underlying type system as of .NET 8 makes
| them equally possible, a guest language could choose to
| emit ref struct closures that reference values on stack,
| but C# can never take a such change because it would be
| massively breaking, a mention goes to .NET monomorphizing
| struct generics in the exact same way it happens in
| Rust), fearless concurrency, access to a large set of
| tools that already serve C/C++ and confidence that LLVM
| is going to be much more robust against complex code, and
| of course deterministic memory reclamation that gives it
| signature low memory footprint. Rust is systems-
| programming-first, while C# is systems-programming-
| strong-second.
|
| Other than that, C# has good support for features that
| allow you to write allocation-free or manual memory
| management reliant code. It also has direct counterpart
| to Rust's slice - Span<T> which transparently
| interoperates with both managed and unmananged memory.
| orf wrote:
| > but C# can never take a such change because it would be
| massively breaking
|
| Out of interest, why?
| riquito wrote:
| I'm sure that .NET has all libraries you'll need and to
| absolutely need one from a different language, whatever it
| is, it's a pretty niche case (e.g. perhaps the extremely
| good Rust `regex` library is faster, but it would hardly be
| worth the extra complexity in the general case).
|
| I think is more common that you have some in-house library
| in a different language (Rust in this case) and you want to
| reuse them without rewriting them.
| tcfhgj wrote:
| matrix-rust-sdk -> build a Matrix client in the native
| platform for Windows
| pjmlp wrote:
| In theory, the compiler could do the same as C++/CLI, and
| output safe Assemblies when specific code patterns aren't
| used.
| zamalek wrote:
| AFAIK, the IJW bits of the CLR are exclusive to Windows.
| neonsunset wrote:
| And strongly in a "do not use unless you must" category
| too.
| pjmlp wrote:
| Still easier than dealing with P/Invoke or COM interop
| for C++ libraries, for C++ skilled devs.
|
| Pity that never made the cross platform jump.
| neonsunset wrote:
| Give this tool a try:
| https://github.com/dotnet/ClangSharp?tab=readme-ov-
| file#gene...
|
| Just specify the headers to generate bindings for, and
| then use the generated interop code. Not too different
| from importing them as it was in the past.
| pjmlp wrote:
| What is exclusive is the Visual C++ backend, because of
| the usual politics, C++ stuff is not under .NET team.
|
| Likewise the whole WinRT/UWP, .NET Native and C++/CX,
| were under WinDev umbrella, not DevDiv.
|
| Which is why there is this schizophrenic way of how .NET
| is currently handled on Windows desktop.
| zamalek wrote:
| I guess another option would be to store the native code
| as an assembly manifest stream, and cast that to a
| delegate at runtime. That would achieve much the same
| thing as IJW without the proprietary bits.
| neonsunset wrote:
| The concept of "verifiable code" is effectively dead - even
| C#'s own syntax is sometimes desugared into what one could
| consider "unsafe" code in terms of feature use. Unsafe code
| is safe when used correctly, it does not imply the reliance
| on undefined or implementation-defined behavior :)
|
| For all intents and purposes, the non-unsafe subset of Rust
| is a safe language, and the distinction pretty much does not
| exist at the IL level.
| asveikau wrote:
| If I read TFA correctly it looks like they're doing codegen
| to IL (which is analogous to Java bytecode, but for .net),
| which would probably mean your rust code is subject to GC?
|
| It seems like you would get rid of performance benefits of
| rust.
|
| But .net can do unsafe pointer operations and it can pin
| objects to avoid GC (they call it "handles" iirc).
| giancarlostoro wrote:
| This is really neat, I always wanted to see other languages
| target .NET much like the JVM was a popular platform to target.
| Considering .NET is fully MIT licensed I am surprised we dont see
| more languages that target .NET
| pjmlp wrote:
| That is why CLR used to mean Common Language Runtime, and there
| were so many languages on the launch event and .NET SDK bundled
| on computer magazines back in 2001.
|
| Then the Windows only focus (for a while there was Rotor), and
| Microsoft being Microsoft, all that interest faded away and
| people focused on the JVM, even though MSIL was designed for
| all kind of languages (well dynamic came later with Iron
| languages and DLR), including C and C++.
|
| Nowadays CLR almost feels to have changed into C# Language
| Runtime, given the C# centric decision on modern .NET design.
| neonsunset wrote:
| While "C# Language Runtime" as a joke term certainly exists,
| most runtime improvements benefit all languages that target
| it, individual changes would have different impact on
| different languages but that's expected. It is likely further
| devirt and escape analysis work will have greater impact on
| F# for example.
| pjmlp wrote:
| As mentioned, I am waiting for .NET 9 final release notes
| in November.
|
| Also a solution for code generators, analysers,
| interceptors usage in .NET libraries and how to consume
| them from F#, some day, if ever.
| debugnik wrote:
| > most runtime improvements benefit all languages that
| target it
|
| And most CIL ABI additions to the CLR driven by C# totally
| break them, because the C# ecosystem adopts them
| immediately (recently even breaking changes in the shared
| framework!), and there's no modern equivalent to the Common
| Language Specification.
|
| Plus, no library writer would care if there was a CLS 2.0
| because every CLR language other than C# and F# is in
| maintenance mode or simply abandoned.
| aninteger wrote:
| > Nowadays CLR almost feels to have changed into C# Language
| Runtime, given the C# centric decision on modern .NET design.
|
| Definitely! VB.Net is basically "dead" and F# will never
| really reach critical mass.
| jjtheblunt wrote:
| F# features creep slowly into C#, though, I feel. (as those
| of Scala would creep into Java at a delay)
| neonsunset wrote:
| Historical precedent and anti-.NET bias - CLI/CIL is a much
| more powerful and flexible bytecode target than JVM, but it is
| also not as well-documented with fewer guest languages and, as
| a result, community know-how. With that said, it really is a
| breath of fresh air to see projects like this one, alongside
| ongoing work on F#, the main "other" language of .NET, and a
| couple small toy-like languages like Draco. There are also IKVM
| and ClojureCLR/ClojureCLR.Next.
| layer8 wrote:
| Microsoft didn't manage to have Visual Basic target .NET
| without turning its semantics into C# with different syntax, so
| this will be interesting to see.
| moomin wrote:
| Anyone remember J#?
| danielovichdk wrote:
| IronRuby?
| giancarlostoro wrote:
| That was a in-between for J++ their Java hard fork.
| aidenn0 wrote:
| Before Rich made Clojure for the JVM, he wrote dotLisp[1] for
| the CLR. Not long after Clojure was JVM hosted, it was also CLR
| hosted[2]. One of my first experiences with ML was F#[3], a ML
| variant that targets the CLR. These all predate the MIT
| licensed .net, but prior to that there was mono, which was also
| MIT licensed.
|
| 1: https://dotlisp.sourceforge.net/dotlisp.htm
|
| 2: https://github.com/clojure/clojure-clr
|
| 3: https://fsharp.org/
| aninteger wrote:
| The lack of a debugger (except for Microsoft's propriety one in
| VS Code) probably limits the language a bit on open source
| operating systems.
| bangaladore wrote:
| What does Rider use? I assume it's not a proprietary MS one?
| Or did they license it?
| neonsunset wrote:
| They use their own in-house implementation. There's an OSS
| alternative from Samsung
| https://github.com/Samsung/netcoredbg but I haven't heard
| of anyone using it.
|
| In general, the debugger is not intentionally made
| unavailable but rather the "properietary" one is just the
| original Visual Studio debugger extracted into a standalone
| package adapted to cross-platform.
|
| Other than that, CoreCLR exposes rich debugger API, and
| debugger implementations just integrate with it, there are
| no "private bits" that would make this task insurmountable,
| there was just not much need to do so so far, and _some_
| Linux folks (as evidenced by skimming through other .NET
| submissions here) tend to have irrational and
| unsubstantiated hatred towards .NET which hinders otherwise
| positive community efforts.
| jen20 wrote:
| > debugger is not intentionally made unavailable
|
| > rather the "properietary" one
|
| The fact that it is proprietary intentionally makes it
| unavailable for use outside of Visual Studio and Xamarin
| Studio - this actually caused debugging to be unavailable
| in Rider for a while a few years ago before they built
| their own.
| neonsunset wrote:
| This is a strange statement. That said debugger also
| comes with base C# extension, which is free and debugger
| aside, MIT, in VS Code on all platforms. Xamarin Studio
| and VS for Mac are deprecated.
|
| Given the confidence of your reply, one would assume
| you'd know this? Unless it's the exact problem I outlined
| previously, in which case please consider sharing
| grievances about something you do use actively instead,
| rather than what you _think_ are .NET 's issues.
| jen20 wrote:
| A timeline:
|
| - The MS Debugger was use in Rider - thus was perfectly
| functional from a technical perspective.
|
| - It was later discovered that the license was
| proprietary, allowed only for MS products. VS Code is one
| of those. The extension may legally not be used with VS
| Codium or other such telemetry-neutering builds.
|
| - The debugger was removed, and debugging of Core CLR
| apps was unavailable while JetBrains found an alternative
| (which did not take very long).
|
| As I alluded to, the fact that this worked, and was just
| prevented by licensing makes it a construct solely of
| proprietary software licensing. It was well documented at
| the time:
|
| - https://blog.jetbrains.com/dotnet/2017/02/15/rider-
| eap-17-nu...
|
| - https://blog.jetbrains.com/dotnet/2017/02/23/rider-
| eap-18-co... news-about-coreclr-on-windows
|
| As for daily driving: I was the first person outside of
| JetBrains to get hands on Rider. The fact that I don't
| write C# _daily_ in 2024 does not mean I have no first-
| hand knowledge of what was happening in 2016-2018, or
| indeed today.
| neonsunset wrote:
| These events predate .NET Core 3.1, which what I consider
| the baseline where "the new" .NET gotten good enough for
| businesses to migrate to. Before that there was a lot of
| uncertainty, breaking changes and culture shock, the echo
| of which is still felt to this day. Nonetheless, this
| holds little influence on the state of affairs in the
| last few versions, certainly since .NET 5, which, if I
| understand your first reply correctly, is the criticism
| in question.
|
| Would you like to put it against Go for lacking package
| manager, Java for being stuck on version 8 or Rust for
| not having stable language server? /s
|
| Or, to phrase it differently, "this is an issue" - "it
| was an issue in 2018" - "no, you don't get it, it's a
| valid criticism because nothing can ever be improved".
| You see how flawed this argument is?
|
| I'm so tired of these low effort replies here that it's
| just sad, in technical conversations in other contexts
| I'd equally defend another language when someone
| blatantly misconstrues the facts. I don't have a horse in
| this race at this point, it's simply annoying to try to
| converse productively when the quality of replies is this
| low. I should probably spend time elsewhere.
| breakingcups wrote:
| I remember when Delphi could briefly compile to .NET.
| bj-rn wrote:
| Idk if it counts but there is VL, a node based visual
| programming language for .NET.
|
| https://visualprogramming.net
|
| https://thegraybook.vvvv.org/reference/getting-started/dotne...
| bob1029 wrote:
| > I also plan to explain the difficulties with Rust code catching
| arbitrary .NET exceptions
|
| Really looking forward to this one.
| evntdrvn wrote:
| Another LLVM-to-.NET project: https://ericsink.com/tocs/rust.html
| zie1ony wrote:
| In the past I have worked on Solidity -> Rust compiler, to enable
| Solidity on WASM VMs. My pain point was emulation of C3
| inheritence in Rust, which I actually was able to implement with
| a few macros. In Rust -> .NET I'm interested in how he does the
| `DerefMut` trait.
| CodesInChaos wrote:
| > how he does the `DerefMut` trait.
|
| What do you mean by that? A compiler backend isn't even exposed
| to high level concepts like traits.
| zie1ony wrote:
| I was thinking about code to code translation. You are right.
| matharmin wrote:
| As a novice with Rust maintaining a cross-platform library
| written in Rust, I've found panics/unwinding is one of the most
| annoying things to figure out in the builds for various
| platforms.
|
| I'm using nostd and panic=abort to keep the library small (around
| 200kb after being stripped), but it's really not a well-supported
| setup.
|
| Depending on the platform, I get an error that the _Unwind_Resume
| symbol is not defined (despite it not supposed to be needed), or
| if I define it myself I get a duplicate symbol error on other
| platforms. I ended up linking to gcc_eh on Linux just to avoid
| the issue.
|
| I just find it strange that out of all the possible issues with
| using nostd, unwinding is causing the most issues.
| agarwaen163 wrote:
| I have had the same issue writing rust libraries for things
| like performant (Gb/s) network log analyzers. Agree this is one
| of the weak points of the language in my relatively amateur
| Rust experience. I also faced the rare cargo dependency bug,
| but still better than alternatives.
| Arnavion wrote:
| >I get an error that the _Unwind_Resume symbol is not defined
| (despite it not supposed to be needed)
|
| Try `-Z build-std=core` if you're not already doing it.
| an_ko wrote:
| Could you elaborate on why that works, or why it's necessary?
| Arnavion wrote:
| I know little about it and I'm not sure that it works. It
| might.
|
| I do know that for regular std-using programs, std has its
| own panic strategy that it was compiled with, so even if
| you set your own code's panic strategy to abort, it still
| ends up pulling in unwind-related code from libstd. The
| solution to that is to also recompile libstd with the same
| parameters as your own code, which is what `-Z build-std`
| does.
|
| I don't know if the same thing applies even to libcore, ie
| for no_std programs. FWIW, coincidentally I spent yesterday
| making a no_std panic=abort program for a custom
| freestanding target, and the only missing symbols it needed
| from me were memcpy and memcmp, even though the code does
| do panicking things like slice indexing. That program
| requires `-Z build-std=core` since it's for a custom
| freestanding target.
| ilyagr wrote:
| I find the relationship between mutlithreading and panics'
| default behavior confusing.
|
| In a single-threaded program, a panic is not supposed to be
| "caught" and aborts everything. If the _main_ thread panics, the
| program stops.
|
| But in a multi-threaded program, a panic terminates only the
| thread it happened in, and the program is allowed to handle that
| case without termination.
|
| I'm _guessing_ that setting `panic=abort` changes this behavior,
| but I 'm not sure.
|
| Docs: https://doc.rust-lang.org/std/macro.panic.html#current-
| imple..., the third sentence of https://doc.rust-
| lang.org/std/thread/fn.spawn.html
| zamalek wrote:
| Your assumptions about panic=abort are correct, it will simply
| terminate the entire process. The single thread and
| multithreaded behaviors are technically the same. A thread can
| observe the panic of another, as such, in a single threaded
| app, which thread would observe the panic in the main thread?
| There is no other thread to do that.
|
| What you could do is create a single new thread and pretend as
| though its the main thread, observing any panics on the
| original main thread.
|
| Edit: your mental model should be to avoid thinking about
| panics (beyond avoiding them in the first place). Panics are
| supposed to be extremely rare, and typically something that
| would be difficult to recover from. They are not exceptions;
| they are not designed to be caught. The difficulty in dealing
| with them is a feature that prevents anti patterns. If
| something panics _you have a bug._
| SAI_Peregrinus wrote:
| The last paragraph is particularly important!
|
| Catching panics in Rust is meant pretty much only to avoid
| unwinding across an FFI boundary, since that would be
| undefined behavior. Pretty much every other use of
| `catch_unwind` is a mistake, it's not guaranteed to catch all
| panics (they can also just abort) so panics are rather
| different from exceptions. Panics are intended to be useless
| for control flow, unwinding exists to help debugging, and any
| _panic indicates a bug in the invoking program_.
| wild_pointer wrote:
| Why does Rust panic under the hood? Brb reading the post to find
| out!
___________________________________________________________________
(page generated 2024-09-23 23:01 UTC)