2017-06-19 101 views
79

Bu, özellikle x86 veya x64'de değil, ARM'de gerçekleşen bir sorundur. Bir kullanıcı tarafından bildirilen bu problemi yaşadım ve Windows IoT üzerinden Raspberry Pi 2 üzerinde UWP kullanarak yeniden üretmeyi başardım. Bu tür bir sorunu daha önce eşleşmeyen arama kuralları ile görmüştüm, ancak C/Coke bildirimini P/Invoke bildirimde belirtiyorum ve aynı sonuçlarla birlikte yerel tarafa __cdecl eklemeyi açıkça denedim. İşte bazı bilgiler verilmiştir:P/Invoke argümanlarının geçirildiği sırada sıfıra girmesine neden olan ne olabilir?

P/çağır beyanı (reference):

[DllImport(Constants.DllName, CallingConvention = CallingConvention.Cdecl)] 
public static extern FLSliceResult FLEncoder_Finish(FLEncoder* encoder, FLError* outError); 

C# yapılar (reference):

internal unsafe partial struct FLSliceResult 
{ 
    public void* buf; 
    private UIntPtr _size; 

    public ulong size 
    { 
     get { 
      return _size.ToUInt64(); 
     } 
     set { 
      _size = (UIntPtr)value; 
     } 
    } 
} 

internal enum FLError 
{ 
    NoError = 0, 
    MemoryError, 
    OutOfRange, 
    InvalidData, 
    EncodeError, 
    JSONError, 
    UnknownValue, 
    InternalError, 
    NotFound, 
    SharedKeysStateError, 
} 

internal unsafe struct FLEncoder 
{ 
} 

C başlığındaki fonksiyonu (reference)

FLSliceResult FLEncoder_Finish(FLEncoder, FLError*); 

FLSliceResult bazı sorunlara neden olabilir çünkü ben t değeri tarafından döndürüldü ve yerel tarafında bazı C++ şeyler var mı?

Yerel taraftaki yapılar gerçek bilgilere sahiptir, ancak C API'sı için FLEncoder, as an opaque pointer olarak tanımlanmıştır. Yukarıdaki yöntemi x86 ve x64'de çağırdığınızda işler sorunsuz çalışır, ancak ARM'de aşağıdakileri gözlemlerim. Birinci argümanın adresi SECOND argümanının adresidir ve ikinci argüman null (örneğin, C# tarafındaki adresleri kaydettiğimde, örneğin, 0x054f59b8 ve 0x0583f3bc), ancak sonra yerel taraftaki argümanlar 0x0583f3bc ve 0x00000000). Bu tür bir sorun sorununa ne sebep olabilir? Ben stumped çünkü kimse İşte

Ben yeniden üretmek koşmak kodu ... Herhangi bir fikri var mı:

unsafe { 
    var enc = Native.FLEncoder_New(); 
    Native.FLEncoder_BeginDict(enc, 1); 
    Native.FLEncoder_WriteKey(enc, "answer"); 
    Native.FLEncoder_WriteInt(enc, 42); 
    Native.FLEncoder_EndDict(enc); 
    FLError err; 
    NativeRaw.FLEncoder_Finish(enc, &err); 
    Native.FLEncoder_Free(enc); 
} 

aşağıdaki ile C++ app Koşu çalışıyor:

auto enc = FLEncoder_New(); 
FLEncoder_BeginDict(enc, 1); 
FLEncoder_WriteKey(enc, FLSTR("answer")); 
FLEncoder_WriteInt(enc, 42); 
FLEncoder_EndDict(enc); 
FLError err; 
auto result = FLEncoder_Finish(enc, &err); 
FLEncoder_Free(enc); 

Bu mantık, en son developer build ile kazayı tetikleyebilir ancak maalesef, Nuget üzerinden yerel hata ayıklama sembollerini nasıl güvenilir bir şekilde sağlayabileceğimi henüz çözemedim (sadece kaynaklardan gelen her şeyi inşa etmek bu gibi görünüyor ...) böylece hata ayıklama biraz awkwar d çünkü hem yerel hem de yönetilen bileşenler oluşturulmalıdır. Birisi denemek istiyorsa, bu işi nasıl kolaylaştıracağınıza dair önerilere açığım. Ancak, bunu daha önce deneyimlemiş veya bunun neden olduğuyla ilgili herhangi bir fikri varsa, lütfen bir cevap ekleyin, teşekkürler! Tabii ki, eğer kimse bir üreme davası isterse (ya kaynak adım atmayı kolaylaştıran bir inşa etmeyi ya da bunu yapmak için zor bir yapı), o zaman bir yorum bırakın ama ben bir tane yapma sürecinden geçmek istemiyorum. Ben C# "sahte" imza ve ardından 2 parametreyi kaldırırsanız: kimse kullanmak için gidiyor eğer

DÜZENLEMEYİ ilginç güncelleme (I kadar popüler gerçek ARM Windows şeyler olduğunu çalıştıran emin değilim) ilki tamam geliyor.

DÜZENLEME 2 İkinci ilginç güncelleme: Ben UIntPtrulong ila boyutunun C# FLSliceResult tanımını değiştirirseniz o zaman argümanlar doğru gelip ... ARM üzerinde size_t imzasız int olmalıdır çünkü mantıklı değil hangi.

EDIT 3 C# tanımına [StructLayout(LayoutKind.Sequential, Size = 12)] eklenmesi de bu işi yapar, ancak NEDEN?Bu mimari için C/C++ içindeki sizeof (FLSliceResult) olması gerektiği gibi 8 döndürür. C# ile aynı boyutta ayarlanması bir çökmeye neden olur, ancak 12'ye ayarlanması çalışmasını sağlar.

DÜZENLEME 4 Test durumunu minimalize ettim, böylece bir C++ test durumu yazabilirim. C# UWP'de başarısız olur, ancak C++ UWP'de başarılı olur.

DÜZENLEME 5Here karşılaştırma için C++ ve C# ikisi için demonte talimatlar verilmiştir (C# gerçi ben almak ne kadar emin değilim bu yüzden çok fazla alarak yan hallettim)

DÜZENLEME 6 Diğer analizler, "iyi" koşarken, yalan söylediğimde ve yapının C# üzerinde 12 bayt olduğunu söylerse, geri dönüş değeri r0'a geçilir, diğer iki ardışıklık r1, r2 aracılığıyla gelir. Ancak, kötü vadede, bu iki bağımsız değişken r0, r1 ve dönüş değeri üzerinden geliyor yani başka bir yerde o kadar fazla kaydırılır (işaretçi yığını?) DÜZENLEME 7

Ben Procedure Call Standard for the ARM Architecture danıştı. Ben şu alıntıyı buldum: "4 bayttan daha büyük veya boyutu, arayan ve callee tarafından statik olarak belirlenemeyen bir Kompozit Tip, işlev çağrıldığında ek bir argüman olarak iletilen bir adreste bellekte saklanır (§5.5, kural A.4). Sonuç için kullanılacak olan bellek, işlev çağrısı sırasında herhangi bir noktada değiştirilebilir. " Bu, r0 'a geçmenin, ek argüman olarak doğru davranışı ifade etmesinin, ilkini (C çağırma sözleşmesinin argüman sayısını belirtmek için bir yolu olmadığı için) işaret ettiğini ima eder. CLR'nin bunun temel 64-bit veri türleriyle ilgili başka bir kural ile kafa karıştırıcı olduğunu merak ediyorum: "Çift kelimelik bir Temel Veri Türü (örn. Uzun, çift ve 64 bitlik kapsayıcı vektörler), r0 içinde döndürülen ve r1."

EDIT 8 Tamam CLR'ye yanlış bir şey yaptığını gösteren birçok kanıt var, bu yüzden bir bug report başvurusunda bulundum. Umarım birisi bu repo: -S.

+1

Yorumlar uzun tartışma için değil; Bu sohbet [sohbet etmek için taşındı] (http://chat.stackoverflow.com/rooms/157727/discussion-on-question-by-borrrden-what-could-cause-p-invoke-arguments-to-be- dışarı). – Andy

+0

60 upvotes ve hiçbir kefaret teklif edildi ... Bu garip –

+6

@MauricioGraciaGutierrez Bu soruya "bu JIT motorunda bir hata" ile cevap verebileceğimi varsayalım (çoğu insanın buraya gelmek için buraya geldiklerini düşünüyorum hatanın çözünürlüğü – borrrden

cevap

1

GH'ye yaptığım konu oldukça uzun zamandır orada oturuyor. Bu davranışın sadece bir böcek olduğuna ve buna bakmak için harcanması gereken daha fazla zamanın kalmadığına inanıyorum.