1. Си / Говнокод #26828

    +2

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    55. 55
    56. 56
    57. 57
    58. 58
    59. 59
    60. 60
    61. 61
    62. 62
    63. 63
    64. 64
    65. 65
    66. 66
    67. 67
    68. 68
    69. 69
    70. 70
    71. 71
    72. 72
    73. 73
    74. 74
    75. 75
    76. 76
    77. 77
    78. 78
    79. 79
    80. 80
    /*
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %                                                                             %
    %                                                                             %
    %                                                                             %
    +  N T M a p M e m o r y                                                      %
    %                                                                             %
    %                                                                             %
    %                                                                             %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    %
    %  Mmap() emulates the Unix method of the same name.
    %
    %  The format of the NTMapMemory method is:
    %
    %    MagickPrivate void *NTMapMemory(char *address,size_t length,int protection,
    %      int access,int file,MagickOffsetType offset)
    %
    */
    MagickPrivate void *NTMapMemory(char *address,size_t length,int protection,
      int flags,int file,MagickOffsetType offset)
    {
      DWORD
        access_mode,
        high_length,
        high_offset,
        low_length,
        low_offset,
        protection_mode;
    
      HANDLE
        file_handle,
        map_handle;
    
      void
        *map;
    
      (void) address;
      access_mode=0;
      file_handle=INVALID_HANDLE_VALUE;
      low_length=(DWORD) (length & 0xFFFFFFFFUL);
      high_length=(DWORD) ((((MagickOffsetType) length) >> 32) & 0xFFFFFFFFUL);
      map_handle=INVALID_HANDLE_VALUE;
      map=(void *) NULL;
      low_offset=(DWORD) (offset & 0xFFFFFFFFUL);
      high_offset=(DWORD) ((offset >> 32) & 0xFFFFFFFFUL);
      protection_mode=0;
      if (protection & PROT_WRITE)
        {
          access_mode=FILE_MAP_WRITE;
          if (!(flags & MAP_PRIVATE))
            protection_mode=PAGE_READWRITE;
          else
            {
              access_mode=FILE_MAP_COPY;
              protection_mode=PAGE_WRITECOPY;
            }
        }
      else
        if (protection & PROT_READ)
          {
            access_mode=FILE_MAP_READ;
            protection_mode=PAGE_READONLY;
          }
      if ((file == -1) && (flags & MAP_ANONYMOUS))
        file_handle=INVALID_HANDLE_VALUE;
      else
        file_handle=(HANDLE) _get_osfhandle(file);
      map_handle=CreateFileMapping(file_handle,0,protection_mode,high_length,
        low_length,0);
      if (map_handle)
        {
          map=(void *) MapViewOfFile(map_handle,access_mode,high_offset,low_offset,
            length);
          CloseHandle(map_handle);
        }
      if (map == (void *) NULL)
        return((void *) ((char *) MAP_FAILED));
      return((void *) ((char *) map));
    }

    Мумуляция «mmap» в «Винде». Это даже работает, если пофиксить две строчки (кто угадает, какие именно, тому ничего).

    Отсюда:
    https://github.com/ImageMagick/ImageMagick/blob/master/MagickCore/nt-base.c

    Запостил: Myxa, 30 Июля 2020

    Комментарии (29) RSS

    • SEO-пост.

      Метки: #виндовоз, #ленсук, #мумуляция, #целыйпитух.
      Ответить
    • Что мне не нравится: злоупотребление типом int и прочими типами неопределённого размера. На некоторых компиляторах можно поймать какой багор.

      Код (offset >> 32) на 32-битном x86 может выполниться вообще без сдвига (посчитается как просто offset), если offset случайно окажется 32-битным, поэтому безопаснее писать так:
      (uint64_t) offset >> 32
      Я всё-таки надеюсь на то, что MagickOffsetType шире 32 бит в любом компиляторе (мне лень искать его определение).

      И ещё у них забавный гольф: (void *) ((char *) map). Зачем такие многократные приведения указателей?
      Ответить
      • Винда ж, откуда там "некоторые конпеляторы". Все под мс по конвеншону подстраиваются.
        Ответить
      • > low_length=(DWORD) (length & 0xFFFFFFFFUL);
        > high_length=(DWORD) ((((MagickOffsetType) length) >> 32) & 0xFFFFFFFFUL);

        Я с определённых пор возненавидел эти байтоёбские сдвиги, маски.
        union и bit fields должны сделать код ГОРАЗДО читабельнее.
        Насчёт Ub и прочих багров не уверен. Но можно вместо union скастить в struct.
        Ответить
        • Битфилды ж implementarion defined. Нахуй и впизду.
          Ответить
          • И в новых стандартах?

            Пиздец. Почему они их не починят?

            >implementarion defined. Нахуй и впизду.
            Ну для MS-онли-компилера может и сойдёт.
            Ответить
            • А как их починишь? Это ж придётся все конпеляторы к одному представлению привести. У кого не такой implementation defined был - тот соснул вместе со всей кодовой базой.
              Ответить
              • > Это ж придётся все конпеляторы к одному представлению привести.
                Да.
                Ну в стандарт записать как надо ложить.
                И пусть ебутся чтобы соотвествовать.
                Ответить
                • Монетку что ли подбросить? Или кто больше заплатит?
                  Ответить
    • Поздно, чтобы вчитываться.

      Но в Луниксе mmap используется не только для файлов, но и как Царская альтернатива mallocу.

      Тут к сожалению не реализован сей нюанс. Какой-то VirtualAlloc.
      Ответить
      • Реализован. Анонимный маппинг же через инвалид хендл в строке 66.
        Ответить
        • Хотел спросить, пытался ли кто-нибудь делать наоборот: MapViewOfFile через mmap. В «Wine» пытались:
          https://github.com/wine-staging/wine-patched/blob/master/dlls/ntdll/virtual.c#L3288
          Ответить
          • С этого кайфанул:
            #define SERVER_START_REQ(type) \
                do { \
                    struct __server_request_info __req; \
                    struct type##_request * const req = &__req.u.req.type##_request; \
                    const struct type##_reply * const reply = &__req.u.reply.type##_reply; \
                    memset( &__req.u.req, 0, sizeof(__req.u.req) ); \
                    __req.u.req.request_header.req = REQ_##type; \
                    __req.data_count = 0; \
                    (void)reply; \
                    do
            
            #define SERVER_END_REQ \
                    while(0); \
                } while(0)

            Использование
            SIZE_T ret = 0;
                    SERVER_START_REQ( get_mapping_committed_range )
                    {
                        req->base   = wine_server_client_ptr( view->base );
                        req->offset = start << page_shift;
                        if (!wine_server_call( req ))
                        {
                            ret = reply->size;
                            if (reply->committed)
                            {
                                *vprot |= VPROT_COMMITTED;
                                set_page_vprot_bits( base, ret, VPROT_COMMITTED, 0 );
                            }
                        }
                    }
                    SERVER_END_REQ;
                    return ret;

            Какая фабрика )))
            Ответить
    • Начнём с того, что они пиздоглазые мудилы в «MapViewOfFile» смещение — вовсе не произвольное число:
      That is, the offset must be a multiple of the allocation granularity.

      Пользователи этого кода рискуют поиметь здоровенные багры. Сам когда-то на это налетал.
      Ответить
      • А в mmap разве произвольное?

        А, понял, в ммап 4к. А в винде 64к.
        Ответить
        • > А в mmap разве произвольное?
          А, не знал. Ну тогда багры будут с allocation granularity, ага.
          Ответить
          • Да никто не передает туда адрес...

            Кроме ебучего mingw, которое иногда падает на форке из-за того что адрес занят.
            Ответить
            • Ага, после установки некоторых пакетов приходится выполнять rebase, чтобы «mingw» снова мог форкать.

              Точнее, не в «mingw», а в «MSYS» (позиксовый слой для «mingw») и в «Cygwin».
              Ответить
              • >после установки некоторых пакетов приходится выполнять rebase, чтобы «mingw» снова мог форкать
                Ой, помню этот багор.

                И даже не после установки. А во время работы. Собираешь что-то мейком: хуяк система залипла.

                Я ещё тогда на 32-битной системе был, это ОЧЕНЬ сильно раздражало. Т.к. виртуальной памяти было не так много.
                Ответить
            • Дык не адрес, а смещение в файле.
              Ответить
              • А, туплю. Ну кстати смещение в mmap тоже выровнено должно быть.
                Ответить
              • То есть если всегда мапить файлы с нулевого смещения, то дефект реализации не заметишь?
                Ответить
                • Подтверждаю.
                  Впрочем, я сейчас в эту портянку вчитываться не хочу, мне ещё спать идти, желательно без кошмаров про превращение в итератор DWORD64. Так что там могут и другие багры быть.
                  Ответить
                  • Затем заставляют представить DWORD64. Неподготовленный человек боится представить DWORD64 так как некоторые участки подсознания не могут совместить DWORD и 64. Этот страх подпитывает страх суицида и разрушение чёткости логики.

                    Говорят, что для того, чтобы это прекратилось необходимо использовать DWORDLONG.
                    Ответить
        • For mmap(), offset must be a multiple of the underlying huge page size.  The system automatically aligns length to be a multiple of the underlying huge page size.
          
          offset must be a multiple of the page size as returned by sysconf(_SC_PAGE_SIZE).
          
           For mmap(), offset must be a multiple of the underlying huge page size.  
          The system automatically aligns length to be a multiple of the underlying huge page size.
          
          Library/kernel differences
                 This  page  describes the interface provided by the glibc mmap() wrapper function.  Originally, this function invoked a system call of the same name.  Since kernel 2.4, that
                 system call has been superseded by mmap2(2), and nowadays the glibc mmap() wrapper function invokes mmap2(2) with a suitably adjusted value for offset.
          Ответить
        • >А, понял, в ммап 4к
          Вот хуй.
          Если там huge pages, то может быть и 2Mb и 4Mb (емнип на армах).
          Ответить
    • > ((void *) ((char *) map))

      А зачем?
      Ответить
      • Чтоб было. Там и так изначально был void* кстати.
        Ответить

    Добавить комментарий