snuk182 / nuklear-backend-gdi

Apache License 2.0
6 stars 2 forks source link

Only support x86_64 toolchains? #1

Open lynnux opened 6 years ago

lynnux commented 6 years ago

Seems https://github.com/snuk182/nuklear-test/tree/gdi depends this library. Works great using nightly-x86_64-pc-windows-msvc, but after switched to nightly-i686-pc-windows-msvc, I got these errors:

error[E0308]: mismatched types
    --> C:\Users\lynnux\.cargo\registry\src\mirrors.ustc.edu.cn-15f9db60536bad60
\nuklear-backend-gdi-0.1.1\src/lib.rs:1013:40
     |
1013 |                     let size = (size / mem::size_of::<winapi::wchar_t>()
as u64) as i32;
     |                                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^ expected u32, found u64

error[E0277]: the trait bound `u32: std::ops::Div<u64>` is not satisfied
    --> C:\Users\lynnux\.cargo\registry\src\mirrors.ustc.edu.cn-15f9db60536bad60
\nuklear-backend-gdi-0.1.1\src/lib.rs:1013:38
     |
1013 |                     let size = (size / mem::size_of::<winapi::wchar_t>()
as u64) as i32;
     |                                      ^ no implementation for `u32 / u64`
     |
     = help: the trait `std::ops::Div<u64>` is not implemented for `u32`

error[E0308]: mismatched types
    --> C:\Users\lynnux\.cargo\registry\src\mirrors.ustc.edu.cn-15f9db60536bad60
\nuklear-backend-gdi-0.1.1\src/lib.rs:1049:45
     |
1049 |                                             ((wsize + 1) * mem::size_of::
<winapi::wchar_t>() as i32) as u64); // 2 = GMEM_MOVEABLE
     |                                             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected u32, found u64
     |
     = help: here are some functions which might fulfill your needs:
             - .count_ones()
             - .count_zeros()
             - .leading_zeros()
             - .trailing_zeros()

error: aborting due to 3 previous errors

error: Could not compile `nuklear-backend-gdi`.

To learn more, run the command again with --verbose.
snuk182 commented 6 years ago

https://github.com/snuk182/nuklear-backend-gdi/commit/50254b41bf6a463395ecde1cc28ec21840e33687 https://crates.io/crates/nuklear-backend-gdi/0.1.2 Should work now.

lynnux commented 6 years ago

Built OK, but crash when running, stack (from x64dbg with symbols):

Address  To       From     Size Comment                                     Party 
003D8AD0 0162F563 01647DAB 14   t.nk_buffer_init+9B                         User
003D8AE4 015147B5 0162F563 7660 t.nk_init+53                                User
003E0144 0146B35A 015147B5 7758 t.nuklear_rust::NkContext::new+65           User
003E789C 0143F041 0146B35A 81CC t.nuklear_backend_gdi::bundle+25A           User
003EFA68 016273FC 0143F041 34   t.t::main+B1                                User
003EFA9C 01626527 016273FC 68   t.panic_unwind::__rust_maybe_catch_panic+3C User
003EFB04 01445062 01626527 14   t.std::rt::lang_start+F7                    User
003EFB18 0166E645 01445062 40   t.main+22                                   User
003EFB58 76B4336A 0166E645 C    t._tmainCRTStartup+FD                       System
003EFB64 77D19902 76B4336A 40   kernel32.BaseThreadInitThunk+E              System
003EFBA4 77D198D5 77D19902 18   ntdll.__RtlUserThreadStart+70               System
003EFBBC 00000000 77D198D5      ntdll._RtlUserThreadStart+1B                User

Seems corresponding C code is:

NK_API void
nk_buffer_init(struct nk_buffer *b, const struct nk_allocator *a,
    nk_size initial_size)
{
    NK_ASSERT(b);
    NK_ASSERT(a);
    NK_ASSERT(initial_size);
    if (!b || !a || !initial_size) return;

    nk_zero(b, sizeof(*b));
    b->type = NK_BUFFER_DYNAMIC;
    b->memory.ptr = a->alloc(a->userdata,0, initial_size);   ----------- crash here, the a->alloc is 0
    b->memory.size = initial_size;
    b->size = initial_size;
    b->grow_factor = 2.0f;
    b->pool = *a;
}

and nk_allocator defined in rust as:

#[repr(C)]
#[derive(Debug, Copy)]
pub struct nk_allocator {
    pub userdata: nk_handle,
    pub alloc: nk_plugin_alloc,
    pub free: nk_plugin_free,
}

the nk_handle is defined as:

#[repr(C)]
#[derive(Debug, Default, Copy)]
pub struct nk_handle {
    pub ptr: __BindgenUnionField<*mut ::std::os::raw::c_void>,
    pub id: __BindgenUnionField<::std::os::raw::c_int>,
    pub bindgen_union_field: u64,
}

but nk_handle defined in C is : typedef union {void *ptr; int id;} nk_handle; , when built by i686 toolchain, is should take only 4 bytes same as u32, so this maybe the reason. And I temporary modified the struct in the cargo source as follow:

#[repr(C)]
#[derive(Debug, Default, Copy)]
pub struct nk_handle {
    pub ptr: __BindgenUnionField<*mut ::std::os::raw::c_void>,
    pub id: __BindgenUnionField<::std::os::raw::c_int>,
    pub bindgen_union_field: u32,
}

It works OK built by i686 toolchain!

snuk182 commented 6 years ago

Thanks for the investigation! Dropped another fix, please try it. https://github.com/snuk182/nuklear-rust/commit/20ee23e9340a4cf5ac61862dfe60198de279eb77 https://crates.io/crates/nuklear-rust/0.3.2

lynnux commented 6 years ago

still crash, but let nk_style_item_data use u64 will be OK.

pub struct nk_image {
    pub handle: nk_handle,   // 4 bytes 
    pub w: ::std::os::raw::c_ushort, // 2 bytes 
    pub h: ::std::os::raw::c_ushort, // 2 bytes
    pub region: [::std::os::raw::c_ushort; 4usize], // 8 bytes
}

on i686 it's at least use 4+2+2+8=16

pub struct nk_style_item_data {
    pub image: __BindgenUnionField<nk_image>,
    pub color: __BindgenUnionField<nk_color>,
    pub bindgen_union_field: [usize; 3usize],  // on i686, 4*3 = 12 not enough
}

don't know how bindgen generate these code, maybe there a portable way to generate code support both i686 and x86_64?

snuk182 commented 6 years ago

While untagged unions are not supported in stable, bindgen makes them with sorta illegal and unsafe way. When I have more time to dig into that, I will check it closer. So far I removed the two other usize's.