c2rust
c2rust copied to clipboard
`rustc_wrapper` is invoked twice during dynamic instrumentation
This causes the runtime to get finalized twice. The first time this occurs, it's during the collection of instrumentation points which causes the built-up set of MirLocs to get drained prematurely. This causes crashes when building the pointer derivation graph because of out-of-index access when attempting to process generated lighttpd events.
This issue needs #582 to reproduce, to get past #570.
I was only able to reproduce this once after running it a bunch of times, but after a rm -rf instrument.target, it works again, and I haven't been able to reproduce it.
Now I'm able to reproduce it. I think I may have just been not waiting long enough.
The error, I think, is because lighttpd builds two crates, rust (a staticlib) and server (a bin). These happen in separate c2rust-instrument-as-rustc-wrapper invocations, and thus the metadata file is written to twice. We need to combine these writes somehow instead of overwriting them, and note that cargo may invoke the rustc wrapper in parallel. There are two ways to do this that I see:
-
For each
rustcwrapper call,openin append mode, serialize to aVec<u8>, and then do a singlewrite(notwrite_all). If thewritedoesn't write all of its data, panic, as only singlewrites are atomic. This should be fine unless there is a signal that interrupts thewrite(or are there other cases the fullwritewouldn't go through?). This will leave consecutiveMetadatas in the file, so when reading, we need to keep deserializingMetadatas until we reach the end of the file. -
For each
rustcwrapper call, write theMetadatato a file like${crate_name}.${metadata}or${metadata}/${crate_name}. Then in thecargowrapper, oncecargoand therustcwrappers have run, read all of those files in, merge them in-memory, and then a mergedMetadatato the original$metadatafile.
Which one do people think is preferable?
Option 1 seems brittle. I wouldn't be surprised if some systems set arbitrary limits on how much data can be written in a single write call. Linux has such a limit, though it's high enough not to be a problem here (most likely):
On Linux, write() (and similar system calls) will transfer at most 0x7ffff000 (2,147,479,552) bytes, returning the number of bytes actually transferred. (This is true on both 32-bit and 64-bit systems.)
Do you know if there's a way to write all bytes or 0 bytes? I can split up writes into smaller chunks.
I don't think there's a standard API for that.