Забавные новости 0й-Ti :)

Тема в разделе "WASM.HEAP", создана пользователем UbIvItS, 18 июн 2018.

Статус темы:
Закрыта.
  1. UbIvItS

    UbIvItS Well-Known Member

    Публикаций:
    0
    Регистрация:
    5 янв 2007
    Сообщения:
    6.241
    rmn, и тут коварный Вопрос == а если освободили ресурс два раза??? :)
     
  2. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.348
    Вы пишете его неправильно :)
    Объект владелец не получает сырой ресурс снаружи. Все, что приходит снаружи и переходит под контроль объекта, должно иметь счетчик ссылок. В объекте делаем AddRef полученному объекту, затем Release текущему, который храним и присваиваем.
    --- Сообщение объединено, 21 ноя 2023 ---
    Значит рукожоп и освободил его не там, где положено. После того, как ресурс корректно освобожден, его адреса уже нигде нет, кроме того кода, который его только что освободил.
     
  3. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.460
    Адрес:
    Россия, Нижний Новгород
    А покажи, как бы ты это сделал для хэндла файла
     
  4. UbIvItS

    UbIvItS Well-Known Member

    Публикаций:
    0
    Регистрация:
    5 янв 2007
    Сообщения:
    6.241
    сколько ты счётчиков не лепи, а при многопоточке ресурс могут освободить кучу раз, вот тебе и use-after-free :crazy::blush2:
    --- Сообщение объединено, 21 ноя 2023 ---
    ахЪЪЪ, этот дивный идеальный мир, коего нам никода не увидеть :) для многопоточек никаких идеальных решений, окромя даблЧека не было и нет, но и даблЧек имеет кучу недостатков - больше лагов и нередко секура становится хуже, пч образуются теневые каналы управления корневыми ресурсами. :)
     
  5. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.348
    Я бы это не делал для хендла файла. Я делаю класс File, который хранит у себя приватно хендл и предоставляет все возможные методы для работы с этим хендлом. Если нужен второй объект класса File, который работает с тем же файлом - это задача первого объекта создать дубликат своего приватного хендла, создать новый объект File и присунуть ему приватного члена.

    Ты втираешь мне какую-то дичь :) Это просто невозможно сделать.
     
  6. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.460
    Адрес:
    Россия, Нижний Новгород
    А покажи, как это будет выглядеть в коде
     
  7. UbIvItS

    UbIvItS Well-Known Member

    Публикаций:
    0
    Регистрация:
    5 янв 2007
    Сообщения:
    6.241
    а что именно невозможно? time-of-check time-of-use одно это чего стоит :)
     
  8. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.348
    Код (C):
    1.  
    2. /*
    3.     rtl/file.h
    4. */
    5. #ifndef _rtl_file_h_included_
    6. #define _rtl_file_h_included_
    7.  
    8. #include <rtl/types.h>
    9. #include <stdarg.h>
    10.  
    11. BEGIN_CDECLS
    12.  
    13. /* -------------------------------------------------------------------------- */
    14.  
    15. #define RTL_INVALID_FILE_SIZE   ((uint64_t)-1)
    16. #define RTL_INVALID_FILE_POS    ((uint64_t)-1)
    17.  
    18. /* -------------------------------------------------------------------------- */
    19.  
    20. typedef struct _RTL_FILE* file_t;
    21.  
    22. /* -------------------------------------------------------------------------- */
    23.  
    24. RTL_API file_t      file_open           (const char* fileName, bool_t readOnly, bool_t exclusive, uint32_t* error);
    25. RTL_API file_t      file_create         (const char* fileName, bool_t ifNotExist, bool_t exclusive, uint32_t* error);
    26.  
    27. RTL_API file_t      wfile_open          (const wchar_t* fileName, bool_t readOnly, bool_t exclusive, uint32_t* error);
    28. RTL_API file_t      wfile_create        (const wchar_t* fileName, bool_t ifNotExist, bool_t exclusive, uint32_t* error);
    29.  
    30. RTL_API void        file_close          (file_t file);
    31.  
    32. RTL_API uint32_t    file_error          (file_t file);
    33.  
    34. RTL_API uint64_t    file_size           (file_t file);
    35. RTL_API uint64_t    file_size_by_name   (const char* fileName, uint32_t* error);
    36. RTL_API uint64_t    wfile_size_by_name  (const wchar_t* fileName, uint32_t* error);
    37.  
    38. RTL_API uint64_t    file_pos            (file_t file);
    39. RTL_API bool_t      file_set_pos        (file_t file, uint64_t pos);
    40.  
    41. RTL_API bool_t      file_read           (file_t file, void* buffer, uint32_t size);
    42. RTL_API bool_t      file_read_at        (file_t file, uint64_t pos, void* buffer, uint32_t size);
    43.  
    44. RTL_API char*       file_read_line      (file_t file, uint32_t* length);
    45. RTL_API char*       file_read_line_at   (file_t file, uint64_t pos, uint32_t* length);
    46.  
    47. RTL_API wchar_t*    wfile_read_line     (file_t file, uint32_t* length);
    48. RTL_API wchar_t*    wfile_read_line_at  (file_t file, uint64_t pos, uint32_t* length);
    49.  
    50. RTL_API bool_t      file_write          (file_t file, const void* data, uint32_t size);
    51. RTL_API bool_t      file_write_at       (file_t file, uint64_t pos, const void* data, uint32_t size);
    52.  
    53. RTL_API bool_t      file_vprintf        (file_t file, const char* format, va_list args);
    54. RTL_API bool_t      file_vprintf_at     (file_t file, uint64_t pos, const char* format, va_list args);
    55.  
    56. RTL_API bool_t      file_printf         (file_t file, const char* format, ...);
    57. RTL_API bool_t      file_printf_at      (file_t file, uint64_t pos, const char* format, ...);
    58.  
    59. RTL_API bool_t      wfile_vprintf       (file_t file, const wchar_t* format, va_list args);
    60. RTL_API bool_t      wfile_vprintf_at    (file_t file, uint64_t pos, const wchar_t* format, va_list args);
    61.  
    62. RTL_API bool_t      wfile_printf        (file_t file, const wchar_t* format, ...);
    63. RTL_API bool_t      wfile_printf_at     (file_t file, uint64_t pos, const wchar_t* format, ...);
    64.  
    65. RTL_API void*       file_load           (const char* fileName, uint32_t* size);
    66. RTL_API bool_t      file_save           (const char* fileName, const void* data, uint32_t size);
    67.  
    68. RTL_API void*       wfile_load          (const wchar_t* fileName, uint32_t* size);
    69. RTL_API bool_t      wfile_save          (const wchar_t* fileName, const void* data, uint32_t size);
    70.  
    71. /* -------------------------------------------------------------------------- */
    72.  
    73. END_CDECLS
    74.  
    75. #endif /* _rtl_file_h_included_ */
    76.  
    Хендл скрыт объектом-оберткой. CloseHandle() для хендла файла джва раза вызван не будет никогда, я гарантирую :)
    --- Сообщение объединено, 21 ноя 2023 ---
    Смотри:
    Код (Text):
    1.  
    2. Enter ();
    3. ReleaseResource (resource);
    4. resource = NULL;
    5. Leave ();
    6.  
    Пользуйся :)
     
  9. UbIvItS

    UbIvItS Well-Known Member

    Публикаций:
    0
    Регистрация:
    5 янв 2007
    Сообщения:
    6.241
    чтобы фри нельзя было просто так два раза вызвать, там не просто счётчик должен быть, а передаваться айди клиента и фри проверяет локальный счётчик относительно айди клиента.. однако, там тоже Вопрос про надёжное хранение и передачу айди :)
     
  10. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.348
    Чиво, блдь? :) Кокой еще айди клиента? Счетчик атомарно уменьшаем и получаем результирующее значение. Если 0, тот кто нас вызвал - единственный, кто имеет указатель на наш объект. Больше вызовов Release гарантированно не будет.
     
  11. q2e74

    q2e74 Active Member

    Публикаций:
    0
    Регистрация:
    18 окт 2018
    Сообщения:
    999
    первые две минуты - смешно :) чего это они так разудевлялись?
     
  12. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.460
    Адрес:
    Россия, Нижний Новгород
    Пустые массивы, кстати, в C++ не стандартизованы: если поставить предупреждения чуть строже дефолтных, компиляторы будут на такие массивы ругаться.

    Хм, а как в этом участвует счётчик ссылок? Тебе ведь ничто не запретит сделать так:
    Код (C++):
    1.  
    2. file_t fileOwner1 = file_open("file.txt");
    3. file_t fileOwner2 = fileOwner1;
    4. file_close(fileOwner1);
    5. // fileOwner2 уже невалиден
    6.  
    В чём мем?

    И тебе приходится писать close на каждый open...
     
    q2e74 нравится это.
  13. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    875
    В нормально написанном коде такого быть не может. Каждая переменная увеличивает счетчик ссылок. Я согласен с rmn что объект должен иметь счетчик ссылок (в моих кодах практически все объекты имеют его).

    Одна проблема только с ними бывает - круговая ссылка, но решается через слабые ссылки. К примеру есть коллекция объектов каждый объект которой должен иметь ссылку на родителя, такое может понадобится для тех же итераторов. Вот пример из реального кода:

    Код (C):
    1. typedef struct _TItem TItem;
    2.  
    3. struct _TItem {
    4.     PBYTE pbKey;
    5.     IGenericObject *pObj;
    6.     TItem *pNext;
    7.     TItem *pNextEnum;
    8. };
    9.  
    10. typedef struct _CHashTable {
    11.  
    12.     #define TABLE_SIZE    977
    13.  
    14.     IHashTableVtbl *pVtbl;
    15.     UINT m_uRefCtr;
    16.     TItem m_pTable[TABLE_SIZE];
    17.     TItem *m_pFirst;
    18.     TItem *m_pLast;
    19.     UINT m_nCount;
    20.     SIZE_T m_szKey;
    21.     IList *m_pEnums;
    22.     BOOL m_bWeakRefs;
    23.  
    24. } CHashTable;
    25.  
    26. UINT CHashTable_AddRef(CHashTable* pThis);
    27. UINT CHashTable_Release(CHashTable* pThis);
    28. HRESULT CHashTable_Add(CHashTable* pThis, PVOID pvObj, PVOID pvKey);
    29. HRESULT CHashTable_Remove(CHashTable* pThis, PVOID pvKey);
    30. VOID CHashTable_Clear(CHashTable* pThis);
    31. UINT CHashTable_get_Count(CHashTable* pThis);
    32. HRESULT CHashTable_get_Item(CHashTable* pThis, PVOID pvKey, PVOID* ppvRet);
    33. HRESULT CHashTable_set_Item(CHashTable* pThis, PVOID pvKey, PVOID pvObj);
    34. HRESULT CHashTable_CreateEnum(CHashTable* pThis, IEnumerator **ppRet);
    35. HRESULT CHashTable_get_Keys(CHashTable* pThis, PVOID* pvKeys);
    36. BOOL CHashTable_Exists(CHashTable* pThis, PVOID pvKey);
    37.  
    38. // private
    39.  
    40. VOID CHashTable_InvalidateEnums(CHashTable* pThis);
    41. VOID CHashTable_InvalidateEnum(CHashTable* pThis, IEnumerator *pEnum);
    42.  
    43. typedef struct _CEnum {
    44.     IEnumeratorVtbl *pVtbl;
    45.     UINT m_uRefCtr;
    46.     CHashTable *m_pParent;
    47.     TItem* m_pNext;
    48. } CEnum;
    49.  
    50. static IHashTableVtbl s_tVtbl = {
    51.     (UINT (*)(IHashTable*))CHashTable_AddRef,
    52.     (UINT (*)(IHashTable*))CHashTable_Release,
    53.     (HRESULT (*)(IHashTable*, PVOID, PVOID))CHashTable_Add,
    54.     (HRESULT (*)(IHashTable*, PVOID))CHashTable_Remove,
    55.     (VOID (*)(IHashTable*))CHashTable_Clear,
    56.     (UINT (*)(IHashTable*))CHashTable_get_Count,
    57.     (HRESULT (*)(IHashTable*, PVOID, PVOID*))CHashTable_get_Item,
    58.     (HRESULT (*)(IHashTable*, PVOID, PVOID))CHashTable_set_Item,
    59.     (HRESULT (*)(IHashTable*, IEnumerator **))CHashTable_CreateEnum,
    60.     (HRESULT (*)(IHashTable*, PVOID*))CHashTable_get_Keys,
    61.     (BOOL (*)(IHashTable*, PVOID))CHashTable_Exists
    62. };
    63.  
    64. UINT CEnum_AddRef(CEnum* pThis);
    65. UINT CEnum_Release(CEnum* pThis);
    66. HRESULT CEnum_Reset(CEnum* pThis);
    67. HRESULT CEnum_Next(CEnum* pThis, UINT uCount, PVOID *ppvRet, UINT *pFetched);
    68.  
    69. static IEnumeratorVtbl s_CCRoutersEnumVtbl = {
    70.     (UINT (*)(IEnumerator*))CEnum_AddRef,
    71.     (UINT (*)(IEnumerator*))CEnum_Release,
    72.     (HRESULT (*)(IEnumerator*))CEnum_Reset,
    73.     (HRESULT (*)(IEnumerator*, UINT, PVOID *, UINT *))CEnum_Next
    74. };
    Каждый итератор (CEnum) хранит слабую ссылку на родителя. При уничтожении хеш-таблицы, происходит инвалидация всех итераторов и обнуление родителя - так у нас получаются валидные итераторы, но уже с уничтоженной таблицей.
    --- Сообщение объединено, 21 ноя 2023 ---
    Так ведь нельзя, нужно делать AddRef. Делаешь AddRef, а потом присваиваешь переменной fileOwner2.
     
  14. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.348
    Мне здравый смысл запретит :)

    Счетчика ссылок там нет, это просто пример скрытия ресурса, в отношении которого гарантированно не будет use-after-free.
    file_t здесь - сырой указатель. Если мне нужен будет вариант с созданием нового объекта, ссылающегося на тот же файл, то будет добавлена функция
    Код (C):
    1.  
    2. file_t file_clone (file_t file);
    3.  
    внутри которой будет (при необходимости в критической секции) вызван ReOpenFile и выделена новая структура, в которую запишется новый хендл.
    Сырой хендл никогда не выйдет из зоны ответственности и никакой другой хендл ты туда не засунешь.

    Ужас какой :)
     
  15. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.460
    Адрес:
    Россия, Нижний Новгород
    Но это лишний оверхед на сами ссылки, под них надо выделять память. Это явно не то, что мы хотим от обёртки над каким-то ресурсом.
     
  16. Rel

    Rel Well-Known Member

    Публикаций:
    2
    Регистрация:
    11 дек 2008
    Сообщения:
    5.330
    Безотносительно к тебе, но больше всего в элитном Цэ меня забавит то, что все топят за то, что ооп не нужон, но сами в своем элитном цэ эмулируют ооп абстракции большим числом кода, чем это можно было бы сделать в Плюсах.

    Да, но опять же, зачем это делать руками в Цэ, если в тех же Плюсах это за тебя сделает RAII.
     
    q2e74 нравится это.
  17. Thetrik

    Thetrik UA6527P

    Публикаций:
    0
    Регистрация:
    25 июл 2011
    Сообщения:
    875
    Так мы все равно делаем обертку, а счетчик ссылок - это капля в море. Думаю на С как-то обыграть по другому без аналогичного оверхеда не получится.

    Так я и не против плюсов и других ЯП с RAII. Я просто показал как на С обыграть слабые ссылки, просто писать приходится на разных ЯП.
     
  18. HoShiMin

    HoShiMin Well-Known Member

    Публикаций:
    5
    Регистрация:
    17 дек 2016
    Сообщения:
    1.460
    Адрес:
    Россия, Нижний Новгород
    Вообще, началось с того, что я привёл кусочек кода с багом, который встречал на ревью и который допускал сам, чтобы в выгодном свете затем представить раст, мол, смотрите, а там такой баг допустить нельзя.
    Но вы поставили меня в тупик, потому что там я апеллировал к невнимательности или незнанию, но когда интерфейсы, допускающие страшные вещи, пишут осознанно, мне остаётся только руками развести...
     
    q2e74 нравится это.
  19. rmn

    rmn Well-Known Member

    Публикаций:
    0
    Регистрация:
    23 ноя 2004
    Сообщения:
    2.348
    Ну, это у тебя просто непонимание того, что значит писать на сишечке. Думаешь еще, небось, что мы ничего кроме stdlib не используем, да? :)

    Чтобы в ехе попало только то, что мне нужно.
     
  20. UbIvItS

    UbIvItS Well-Known Member

    Публикаций:
    0
    Регистрация:
    5 янв 2007
    Сообщения:
    6.241
    тыщи потоков работают, с разных компов и просто счётчик? :) даже для малой многопоточки полезно в плане отладки.
     
Статус темы:
Закрыта.