-
Notifications
You must be signed in to change notification settings - Fork 122
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
MINIDUMP_CALLBACK_INPUT packing/alignment problem #460
Comments
That pack attribute is there in the metadata. Is this a Rust projection specific issue? |
Weird. I don't know what would have changed in more recent builds for this to show up. I'm about due for a release anyway. And I just noticed my per-arch difference checking didn't notice that pack 4 is on the x64/arm64 but not x86. That might have something to do with it. |
You sure that that struct is not |
Are there any updates on this issue? The windows 0.23.0 crate seems to still have this issue. |
@qrnch-jan @AraHaan This seems to be working great, can we close this issue? I've verified it's annotated correctly in metadata (17.0.15.55535) as well. [dependencies.windows]
version = "0.32.0"
features = [
"Win32_Foundation",
"Win32_Graphics_Dxgi",
"Win32_Storage_FileSystem",
"Win32_System_Kernel",
"Win32_System_Memory",
"Win32_System_Diagnostics_Debug",
] #[test]
fn test_minidump_callback_input_size() {
unsafe {
assert_eq!(std::mem::size_of::<MINIDUMP_CALLBACK_INPUT>(), 1312);
}
} |
The sizes match, though the main problem I was having is still having an issue -- but I need an extra pair of eyes, just to make sure I'm not reading the results wrong. The issue is that I'm getting some very odd values for This is from a C program which I'm using to sanity-check the Rust code's output: BOOL CALLBACK MyMiniDumpCallback(
PVOID pParam,
const PMINIDUMP_CALLBACK_INPUT pInput,
PMINIDUMP_CALLBACK_OUTPUT pOutput)
{
BOOL bRet = FALSE;
int i, j;
const uint8_t *p;
unsigned offs;
/* ... */
offs = (uint8_t*)(&(pInput->CallbackType)) - (uint8_t*)pInput;
printf("%p %d %u offs=%u\n", pInput, (int)pInput->CallbackType,
(unsigned)sizeof(MINIDUMP_CALLBACK_INPUT), offs); I.e. it calculates the offset to the This Rust code: unsafe extern "system" fn minidump_callback(
param: *mut c_void,
input: *const MINIDUMP_CALLBACK_INPUT,
output: *mut MINIDUMP_CALLBACK_OUTPUT
) -> BOOL {
let param = &mut *(param as *mut MDCContext);
// ...
let memberaddr = &(*input).CallbackType as *const _;
let offs = memberaddr as u64 - input as u64;
println!(
"input={:p} {} calltypeoffs={}",
input,
std::mem::size_of::<MINIDUMP_CALLBACK_INPUT>(),
offs
); ... outputs that To me, this looks like the C structure is I'm guessing that marking the relevant structs as |
Got it. I took another look and I must have looked at *_INFORMATION and not *_INPUT. It is indeed missing the packing attribute in metadata. Will get that patched up now. Along with |
@mikebattista @sotteson1 Do you remember what the final outcome of #418 #521 were? That is, what do we do with structures that don't have architecture-specific variants? Target x64 (pack=4) and downstream x86 generators just ignore it? Or do we invent a new type? Or am I discovering the reason this issue is still open? 😆 |
This issue just hit another client. |
What's the status of this old issue? There's another question about the type of the callback field. |
This looks like a duplicate of #1744. The issue is still there in the latest metadata (24.0.1-preview). Originally posted by @tim-weis in microsoft/windows-rs#1892 (comment) |
@sotteson1 / @AArnott for comment. |
I don't understand the question, or it's been resolved long ago. Structs that are the same for all architectures are declared once in the metadata without special attributes. When a struct exists for only a subset of architectures or is declared differently across architectures, it is declared with attributes to indicate which architectures this particular declaration belongs to. The struct may be declared multiple times with unique architecture attributes. In such a case the type may be declared multiple times in the exact same namespace and with the same name, which means projection should take care to select the right declaration based on the target architecture. |
@AArnott's description is consistent with how Rust treats metadata. So I'm guessing there's something else going on here. If someone could clarify that would be great. |
This gets a little hairy for the architecture-specific structures; not sure if the current tooling supports overriding the pack across all those. (The architecture-specific split is still needed as some structures are missing fields, for example the Pad member of |
That doesn't sound right. To illustrate the issue here's both a C++ and Rust implementation that should produce identical output: main.cpp #include <Windows.h>
#include <DbgHelp.h>
#include <cstddef>
#include <format>
#include <cstdio>
int main()
{
std::puts(
std::format("Offset of ProcessHandle: {}",
offsetof(MINIDUMP_CALLBACK_INPUT, ProcessHandle)).c_str()
);
} Compiling and running this from an x64 Visual Studio command prompt yields the following output:
Cargo.toml [package]
name = "minidump"
version = "0.0.0"
edition = "2021"
[dependencies.windows-sys]
version = "0.36.1"
features = [
"Win32_System_Diagnostics_Debug",
"Win32_Foundation",
"Win32_Storage_FileSystem",
"Win32_System_Kernel"
]
[dependencies]
memoffset = "0.6.5" main.rs use windows_sys::Win32::System::Diagnostics::Debug::MINIDUMP_CALLBACK_INPUT;
fn main() {
println!(
"Offset of ProcessHandle: {}",
memoffset::offset_of!(MINIDUMP_CALLBACK_INPUT, ProcessHandle)
);
}
Using the latest |
Thanks for the repro! So the issue is that |
@sotteson1 / @mikebattista is this something we can quickly rectify? This issue has been open for some time and is clearly causing problems for a number of customers. |
Another note on the previous repro that touches on an issue that was discussed here earlier: Adding output for the size of the std::puts(
std::format("Size of MINIDUMP_CALLBACK_INPUT: {}",
sizeof(MINIDUMP_CALLBACK_INPUT)).c_str()
); and println!(
"Size of MINIDUMP_CALLBACK_INPUT: {}",
std::mem::size_of::<MINIDUMP_CALLBACK_INPUT>()
); produces identical output
I would have expected the size of the Rust structure to be larger due to the wider structure packing, so maybe something else is wrong in addition to the missing structure packing attribute (as @riverar noted here). |
Once we have the correct metadata, I'm happy to add cross-arch tests to validate this is Rust. |
Packing aside. The current architecture neutral There's a fun bag of issues here! |
That sort of problem is not new: #725 |
The metadata contains typeref's from neutral APIs to arch-specific APIs, yes. In CsWin32 we always resolve a typeref 'loosely' by checking whether the referenced type is arch-specific and if so, we may look for another declaration of that type with the right architecture on it. Metadata simply isn't great at representing multiple architectures in a single file. The use case I'm thinking of is a neutral struct with a field that is a pointer to an arch-specific struct. When C# targets AnyCPU, we should be able to emit the neutral struct just fine, and simply leave the field pointer as |
Well, @sotteson1 has already said he wants to fix such instances rather than calling it a feature.
A lot of languages (probably most) generate code ahead of time so the kind of fancy "loose typing" you employ in C# isn't necessarily possible for everyone. Either way, this needs to be fixed and ideally done so consistently. |
The loose typing I'm talking about isn't a C# or .NET runtime feature. It's something I do at projection time, and I would expect any projection can do it. The only requirement is that the projection know which CPU architecture is being targeted and that if the project is targeting multiple CPU architectures that unique projections be created for each. But that's a requirement regardless. I think this issue should focus on the packing/alignment problem, which if I read correctly comes from the C parser we're using not recognizing packing settings that don't appear in syntax on the struct itself. Discussing redesigning how arch-specific structs are represented in metadata should probably go in a different issue. |
Hm, what information would you lose? It seems weird that we would do all the work to generate architecture-specific structures and then leave them floating around with no references, instead relying on downstream bindings to "determine if type reference is pointing to the wrong arch and automatically tidy up". |
Consider that struct A is neutral but for a field with a pointer to struct B which is arch-specific. Today, struct A is described in metadata as neutral. If instead the metadata declared A as arch-specific because it references B which is arch-specific, we lose the data that A is actually itself neutral and therefore can be safely represented in an AnyCPU targeted assembly. |
Hey @tannergooding, we're noticing that these two structs from minidumpapiset.h are wrapped by #include <pshpack4.h>, but only one of them is marked with [StructLayout(LayoutKind.Sequential, Pack = 4)] by ClangSharp. Any idea what might be causing that? typedef struct _MINIDUMP_VM_POST_READ_CALLBACK
{
...
} MINIDUMP_VM_POST_READ_CALLBACK, *PMINIDUMP_VM_POST_READ_CALLBACK;
typedef struct _MINIDUMP_CALLBACK_INPUT {
...
} (This looks the same for x86, x64 and arm64) [StructLayout(LayoutKind.Sequential, Pack = 4)]
public unsafe partial struct MINIDUMP_VM_POST_READ_CALLBACK
{
...
}
public partial struct MINIDUMP_CALLBACK_INPUT
{
....
} |
I can take a look later today. I'd guess this is a case where Clang isn't surfacing the relevant information because it matches the expected default alignment -or- potentially that its only present for say 64-bit but the header is being processed as 32-bit or vice-versa. |
Sorry, I found an existing issue in ClangSharp for this @tannergooding. It looks like this sometime happens for 32-bit but never for 64-bit. Since I already scan some headers in multiple architectures, I can for this one and get the correct packing from the 64-bit one. |
Fixed with #1233 |
@sotteson1 There's still the issue of arch-neutral MINIDUMP_CALLBACK_INPUT referencing arch-specific types (e.g. MINIDUMP_THREAD_CALLBACK). Can create a new issue for that, though some of the discussion occurred above. |
I'm running
MiniDumpWriteDump()
in Rust with a callback. Accessing the fields ofMINIDUMP_CALLBACK_INPUT
yields "garbage" values (clearly wrong, but consistent, values). There's a noticeable size discrepancy between the C and Rust structs; it's 1000 in Rust, while it's 1312 in C. The offset of theCallbackType
member is 12 in C and 16 in Rust. The Rust binding does not include apacked(4)
.The entire include file is apparently wrapped in pack(4), but other types in the Rust bindings are missing
packed(4)
, likeMINIDUMP_CALLBACK_OUTPUT
.The text was updated successfully, but these errors were encountered: