এই নিরাপদ কোডটি। নেট কোর 3 এও কাজ করা উচিত?


42

আমি Span<T>সম্ভব হলে হিপ বরাদ্দ এড়ানোর জন্য আমার লাইব্রেরিগুলিকে রিফ্যাক্টর করছি তবে আমি পুরানো ফ্রেমওয়ার্কগুলিকেও টার্গেট হিসাবে আমি কিছু সাধারণ ফ্যালব্যাক সমাধানগুলিও বাস্তবায়ন করছি। তবে এখন আমি একটি অদ্ভুত সমস্যা পেয়েছি এবং। নেট কোর 3 এ আমি কোনও বাগ খুঁজে পেয়েছি বা আমি কোনও অবৈধ কাজ করছি কিনা তা সম্পর্কে আমি নিশ্চিত নই।

সমস্যাটি:

// This returns 1 as expected but cannot be used in older frameworks:
private static uint ReinterpretNew()
{
    Span<byte> bytes = stackalloc byte[4];
    bytes[0] = 1; // FillBytes(bytes);

    // returning bytes as uint:
    return Unsafe.As<byte, uint>(ref bytes.GetPinnableReference());
}

// This returns garbage in .NET Core 3.0 with release build:
private static unsafe uint ReinterpretOld()
{
    byte* bytes = stackalloc byte[4];
    bytes[0] = 1; // FillBytes(bytes);

    // returning bytes as uint:
    return *(uint*)bytes;
}

আকর্ষণীয়ভাবে যথেষ্ট, ReinterpretOldনেট নেট ফ্রেমওয়ার্ক এবং নেট কোর ২.০ এ ভাল কাজ করে (যাতে আমি এর পরেও খুশি হতে পারি), তবুও এটি আমাকে কিছুটা বিরক্ত করে।

BTW। ReinterpretOldএকটি ছোট পরিবর্তন দ্বারা। নেট কোর 3.0 এও ঠিক করা যেতে পারে:

//return *(uint*)bytes;
uint* asUint = (uint*)bytes;
return *asUint;

আমার প্রশ্ন:

এটি কি কোনও বাগ বা ReinterpretOldপুরানো ফ্রেমওয়ার্কগুলিতে কেবল দুর্ঘটনাক্রমে কাজ করে এবং আমি কি তাদের জন্য এই ফিক্সটি প্রয়োগ করব?

মন্তব্য:

  • ডিবাগ বিল্ড। নেট কোর 3.0 এও কাজ করে
  • আমি আবেদন [MethodImpl(MethodImplOptions.NoInlining)]করার চেষ্টা করেছি ReinterpretOldকিন্তু এর কোনও ফল হয়নি।

2
এফওয়াইআই: return Unsafe.As<byte, uint>(ref bytes[0]);বা return MemoryMarshal.Cast<byte, uint>(bytes)[0];- ব্যবহার করার প্রয়োজন নেই GetPinnableReference(); অন্য কিছুটা দেখুন, যদিও
মার্ক গ্র্যাভেল

শার্পল্যাব যদি এটি অন্য কাউকে সহায়তা করে। দুটি সংস্করণ এড়ানো যা Span<T>বিভিন্ন আইএলকে সংকলন করে। আমি মনে করি না আপনি কিছু অবৈধ করছেন: আমি একটি জেআইটি বাগ সন্দেহ করি।
ক্যান্টন 7

আপনি যে আবর্জনা দেখছেন তা কী? আপনি স্থানীয়-ইনিড অক্ষম করতে হ্যাক ব্যবহার করছেন? এই হ্যাকটি উল্লেখযোগ্যভাবে প্রভাব ফেলে stackalloc(যেমন এটি বরাদ্দকৃত জায়গাটি মুছে দেয় না)
মার্ক গ্র্যাভেল

@ ক্যান্টন if যদি তারা একই আইএল সংকলন করে, তবে আমরা এটি নির্ধারণ করতে পারি না এটি একটি জেআইটি বাগ ... যদি আইএল একই হয়, ইত্যাদি ... কোনও সংকলক বাগের মতো আরও কিছু মনে হয়, সম্ভবত কোনও পুরানো সংকলক সহ? গিরিগিরিস: আপনি কীভাবে এটি সংকলন করছেন ঠিক তা ইঙ্গিত করতে পারবেন? উদাহরণস্বরূপ কী এসডিকে? আমি আবর্জনাটি ত্রুটিযুক্ত করতে পারি না
মার্ক গ্র্যাভেল

1
দেখে মনে হচ্ছে স্ট্যাক্যালোক সবসময় শূন্য হয় না: লিঙ্ক
ক্যান্টন 7

উত্তর:


35

ওহ, এটি একটি মজাদার সন্ধান; এখানে যা ঘটছে তা হ'ল আপনার স্থানীয়টি অপ্টিমাইটিভ হচ্ছে - কোনও স্থানীয় লোক অবশিষ্ট নেই, যার অর্থ নেই যে সেখানে নেই .locals init, যার অর্থ অন্যরকমstackalloc আচরণ করে এবং স্থানটি মুছে দেয় না;

private static unsafe uint Reinterpret1()
{
    byte* bytes = stackalloc byte[4];
    bytes[0] = 1;

    return *(uint*)bytes;
}

private static unsafe uint Reinterpret2()
{
    byte* bytes = stackalloc byte[4];
    bytes[0] = 1;

    uint* asUint = (uint*)bytes;
    return *asUint;
}

হয়ে:

.method private hidebysig static uint32 Reinterpret1() cil managed
{
    .maxstack 8
    L_0000: ldc.i4.4 
    L_0001: conv.u 
    L_0002: localloc 
    L_0004: dup 
    L_0005: ldc.i4.1 
    L_0006: stind.i1 
    L_0007: ldind.u4 
    L_0008: ret 
}

.method private hidebysig static uint32 Reinterpret2() cil managed
{
    .maxstack 3
    .locals init (
        [0] uint32* numPtr)
    L_0000: ldc.i4.4 
    L_0001: conv.u 
    L_0002: localloc 
    L_0004: dup 
    L_0005: ldc.i4.1 
    L_0006: stind.i1 
    L_0007: stloc.0 
    L_0008: ldloc.0 
    L_0009: ldind.u4 
    L_000a: ret 
}

আমি মনে করি আমি এই বলে যে এটি একটি সংকলক বাগ, বা কমপক্ষে খুশি হব: একটি অনাকাঙ্ক্ষিত পার্শ্ব-প্রতিক্রিয়া এবং আচরণের কারণে পূর্ববর্তী সিদ্ধান্তগুলি "লোকাল থ্রিমটি নির্গত করুন" বলার জন্য রাখা হয়েছিল , বিশেষত চেষ্টা করার জন্য এবং রাখা stackallocবিবেকী - কিন্তু কিনা কম্পাইলার ভাবেন একমত তাদের আপ হয়।

কর্মক্ষেত্রটি হ'ল: stackallocস্থানটিকে অপরিজ্ঞাত হিসাবে গণ্য করুন (যা নিখরচায়, আপনি যা বোঝাতে চেয়েছিলেন); যদি আপনি এটি শূন্য হওয়ার প্রত্যাশা করেন: ম্যানুয়ালি এটি শূন্য।


2
মনে হচ্ছে এটির জন্য একটি মুক্ত টিকিট রয়েছে । আমি এটিতে একটি নতুন মন্তব্য যুক্ত করতে যাচ্ছি।
গাইরিগিয়ান কাসেজেগ

হু, আমার সমস্ত কাজ এবং আমি লক্ষ্য করিনি যে প্রথমটি অনুপস্থিত ছিল locals init। সুন্দর.
ক্যান্টন 7

1
@ canton7 যদি আপনি আমার মত হন কিছু, আপনি স্বয়ংক্রিয়ভাবে গত লাফালাফি .maxstackএবং .localsনা নোটিশ, এটা তৈরীর বিশেষত সহজ এটি যে / না সেখানে :)
মার্ক Gravell

1
The content of the newly allocated memory is undefined.এমএসডিএন অনুসারে স্পেসিফিকেশনটি বলে না যে মেমরিটি শূন্য করা উচিত। সুতরাং দেখে মনে হচ্ছে এটি দুর্ঘটনাক্রমে বা চুক্তিহীন আচরণের ফলে কেবল পুরানো কাঠামোয় কাজ করে।
লুয়ান
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.