-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
RFC: Investigate a "postgres target" rust compiler target #32
Comments
Postgres' definition of "TRUSTED" is here: https://www.postgresql.org/docs/14/xplang-install.html
I see little reason for us to go beyond that and inventing our own definition. Like, to me, this says that network access is just fine. Perhaps even the sound card and GPU. |
I will refer to these hypothetical targets This follows the established convention of using the last term in the target tuple to define the ABI and necessary runtime support (usually libc functions) of the target. The fundamental question to answer is, "Is it possible to compile Rust code to a target that uses Postgres's own functions for allocation and the like at the core of its runtime support, thus eliminating the impedance mismatch between Rust's runtime and Postgres's runtime?" |
What about postgres versions? Their headers differ somewhat dramatically at times.
|
I am going to focus on trying to get the latest Postgres working and pretend that doesn't happen in ways that actually impact the extent of alloc/std we want to support, but yes, something like that might need to happen when I stop pretending. |
Since trying to stuff Rust fully "into" the Postgres server's allocation and error handling logic is the main goal for this, I spent a fair amount of time studying Postgres's memory contexts for allocation and the like, how it handles memory allocations and pointers and aborts, how procedural language execution happens, the I didn't see anything that I think will prove to be a blocker and altogether I think it may actually wind up proving even easier than I thought, by, in the crate that PL/Rust code gets compiled into
This likely means we wind up with a postgres-alloc and/or a postgres-panic crate in a workspace somewhere. As far as my understanding currently goes, this would also make the current "dance" around Destructors are not guaranteed to be run. |
True. And in practice I don't know that they'll even come up as "necessary" within the confines of a single pl/rust function. However, if we override the global allocator to use Postgres, it's important to point out that we'll lose the ability to do threading. Postgres is strictly not thread-safe, most especially its MemoryContext system. You might think, "well, we could wrap the global allocator functions in a Mutex", but the overhead aside, we can't control what the main thread does as it's Postgres proper and won't be routed through Rust's global allocator. |
We lose it twice, actually: Rust's libcore doesn't have |
So... @Hoverbear showed me some "hack" examples where you can still pull in |
Alright, there were several delays due to... various points of confusion, some of them entertaining, most of them not, but I have now managed to get a global allocator override working. More of the work was attempting to figure out how to push a message back out effectively so I could prove to myself it was working as intended, honestly. It's enormously crude right now as I just directly inject the allocator's code and the What I haven't done is successfully ungluing and overriding the panic handler... that requires more digging into PGX, because PL/Rust uses PGX to build code for obvious reasons... which means it links in PGX's panic handling code already, which does not play excellently with trying to override the panic handler a second time, causing linking errors. However, this is just solved by taking a hacksaw to PGX and telling it to not ALWAYS add code at various points, so as to make its panic handler modular, which is easily enough done. PL/Rust code does run already with these changes, it's just now in the awkward position of doing needless work. |
As far as pulling in The way to get around that, I suspect, would be to use a "bare metal" target that corresponds to "use the current platform's binary object format, but without the platform's C runtime". That way, the contents of That would then bring things within striking distance of "actually for real we're just implementing our own |
Knock yourself out: #![no_std]
extern crate std;
fn main() {
let s = std::string::String::from("hi");
std::eprintln!("{s}")
} |
Oh yeah, |
I assume this would also prevent other 3rd party crates that might re-export |
Correct. I confirmed last night that we have to build a "full-fledged" new std instead of a "mere" override, as a |
Currently blocked on #49 which requires a PR to PGX which I had been drafting. Likely need to toggle a feature based on inclusion of the Postgres allocator or not. |
That was unblocked (mostly) and also I got everything building for postgrestd and just need to document and push everything up properly now. This will depend on several forked crates for the first version probably. |
As of #56 a preliminary The main tradeoff things ran up against is that while I was researching things, it proved untenable to actually carve out entire modules of Rust code at compile time (which was discussed out-of-band as a possible desirable), and I was instead eventually forced to shift towards a strategy of using stubs instead (that can still return failure, success, or whatever based on the implementation). |
I've been playing with it this morning and it seems to work quite well!!! |
Yesterday I realized and implemented everything that had to happen to effectuate a new version of the Rust target-specific I haven't explored all the benefits and costs of this implementation yet but it should basically eliminate any questions about safety from Safe Rust while also minimizing the number of forked dependencies needed in the future. |
Main insight from spending a bit of time investigating it today: Aside from blocking off |
Even libc also no longer requires forking with the revised approach! As panic handling currently more or less Just Works (well, after I fixed a few cases which surfaced inadequacies in pgx with respect to "suddenly being used in ways neither it nor Rust were ever really expecting to be used"), I have been spending more time on examining the general concern with regard to One possibility that was brought up is simply running a "pre-build" step where we |
I still want to modularize the existing panic handler code but it does appear to work, and everything seems to work with aarch64 support as well. |
I'd like to see what it would look like to design (develop?) and otherwise maintain a custom rust compilation target for Postgres that could give us a nearly "safe" (as Rust defines it) and "trusted" (as Postgres defines a procedural language) plrust.
As I know very little about this topic, please take these points with a grain of salt, but I suppose we need:
(ie, no disk or socket I/O, etc, etc), mainly no filesystem accesspostmaster
process (ie, no ability to reach into Postgres' memory space, despite us running in it)And some other points of consideration:
malloc
/free
or can we instead use Postgres'palloc/
pfree` functions?Please feel free to add other ideas here.
The text was updated successfully, but these errors were encountered: