zlib.uncompress вызывает исключение в сборке Release

Тема в разделе "LANGS.C", создана пользователем KeSqueer, 18 мар 2011.

  1. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    Собственно, вот код:
    Код (Text):
    1. #include <stdio.h>
    2. #include <stdlib.h>
    3. #include <string.h>
    4. #include <direct.h>
    5.  
    6. #include "zlib/zlib.h"
    7. #pragma comment(lib, "zlib/zdll.lib")
    8.  
    9. #pragma pack(push, 1)
    10.  
    11. typedef struct {
    12.     char version[12];
    13.     long files_count;
    14.     long dirs_count;
    15.     long packed_size;
    16. } VDKHEADER;
    17.  
    18. typedef struct {
    19.     char type;
    20.     char name[128];
    21.     long size;
    22.     long packed_size;
    23.     long content;
    24.     long next;
    25. } VDKRECORD;
    26.  
    27. #pragma pack(pop)
    28.  
    29. FILE *vdk_file;
    30.  
    31. void unpack_dir(long offset, const char *dst_dir) {
    32.     long cur_offset = offset;
    33.     VDKRECORD rec;
    34.     char dst_file_name[_MAX_PATH];
    35.     while (cur_offset) {
    36.         fseek(vdk_file, cur_offset, SEEK_SET);
    37.         fread(&rec, sizeof(rec), 1, vdk_file);
    38.         if (strcmp(rec.name, ".") && strcmp(rec.name, "..")) {
    39.             strcpy_s(dst_file_name, _countof(dst_file_name), dst_dir);
    40.             strcat_s(dst_file_name, _countof(dst_file_name), "\\");
    41.             strcat_s(dst_file_name, _countof(dst_file_name), rec.name);
    42.             switch (rec.type) {
    43.                 case 0: {
    44.                     FILE *dst_file;
    45.                     unsigned long unpacked_size = rec.size, packed_size = rec.packed_size;
    46.                     void *unpacked_buf = malloc(unpacked_size);
    47.                     void *packed_buf = malloc(packed_size);
    48.                     printf("Found file: %s\n", rec.name);
    49.                     printf("Size: %d\n", unpacked_size);
    50.                     printf("Packed size: %d\n\n", packed_size);
    51.                     if (fread(packed_buf, 1, packed_size, vdk_file) == packed_size) {
    52.                         uncompress(unpacked_buf, &unpacked_size, packed_buf, packed_size); // <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
    53.                         fopen_s(&dst_file, dst_file_name, "wb");
    54.                         fwrite(unpacked_buf, 1, unpacked_size, dst_file);
    55.                         fclose(dst_file);
    56.                     }
    57.                     free(unpacked_buf);
    58.                     free(packed_buf);
    59.                     break;
    60.                 }
    61.                 case 1: {
    62.                     printf("Found directory: %s\n", rec.name);
    63.                     _mkdir(dst_file_name);
    64.                     unpack_dir(rec.content, dst_file_name);
    65.                     break;
    66.                 }
    67.             }
    68.  
    69.         }
    70.         cur_offset = rec.next;
    71.     }
    72. }
    73.  
    74. int main(int argc, char *argv[]) {
    75.     VDKHEADER hdr;
    76.     char *vdk_file_name = "D:\\Games\\RequiemRus\\data\\DAT.VDK";
    77.     char *dst_dir_name = "D:\\RQ";
    78.  
    79.     if (fopen_s(&vdk_file, vdk_file_name, "rb") == 0) {
    80.         printf("Archive:\t%s\n", vdk_file_name);
    81.         if (fread(&hdr, sizeof(hdr), 1, vdk_file) == 1) {
    82.             printf("Version:\t%s\n", hdr.version);
    83.             printf("Files count:\t%d\n", hdr.files_count);
    84.             printf("Dirs count:\t%d\n", hdr.dirs_count);
    85.             printf("Size:\t\t%.2f MB\n\n", (float)hdr.packed_size/1024/1024);
    86.             unpack_dir(sizeof(VDKHEADER), dst_dir_name);
    87.         }
    88.         fclose(vdk_file);
    89.     }
    90.     argc;
    91.     argv;
    92.     return 0;
    93. }
    В Debug сборке всё работает прекрасно, переключаю на Release и ловлю исключение ACCESS VIOLATION где-то в недрах zlib.uncompress. Отчего такое может происходить?
    Линковка с zlib динамическая.
    MSVS 2005 SP1, все параметры по-умолчанию (ну за исключением /TC /D "_MBCS")
    Debug версия собирается с Multi-threaded Debug DLL (/MDd), Release версия - с Multi-threaded DLL (/MD). Пробовал менять - результат - нулевой.
     
  2. osox

    osox New Member

    Публикаций:
    0
    Регистрация:
    13 ноя 2009
    Сообщения:
    280
    а что в стеке валидные параметры ? жди пока упадет клик по нужной функции в call stack потом в memory вбиваеш ebp
    (именно буквами вписываеш в поле address)
    формат вывода 4 байта ставиш и все
    указывать будет на сохраненный ebp за ним адрес возврата и параметры следом вот пример для puts
    0x0013FF10 0013ff68 00411304 00415d20
     
  3. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    Попробовал трассировать uncompress:
    Код (Text):
    1. 00402188  push        esi  
    2. 00402189  push        edi  
    3. 0040218A  lea         ecx,[esp+18h]
    4. 0040218E  push        ecx  
    5. 0040218F  push        ebx  
    6. 00402190  call        _uncompress (401000h)
    7. ...
    8. _uncompress:
    9. 00401000  jmp         dword ptr ds:[400000h]
    10. 00401006  nop              
    11. 00401007  nop              
    12. ...
    13. 00905A4D  ???
    14. 00905A4E  ???              
    15. 00905A4F  ???
    Собственно, всё понятно, откуда access violation. Не понятно как так линкер слинковал, и что делать :)
     
  4. osox

    osox New Member

    Публикаций:
    0
    Регистрация:
    13 ноя 2009
    Сообщения:
    280
    можно попробовать добавить __declspec(dllimport)
    тогда вызов напрямую будет генерировать без jmp'а
    вот в release VS2008 без __declspec(dllimport)
    генерирует через jmp как у Вас
    Код (Text):
    1. extern "C" void __stdcall SetConsoleTitleA(const char*);
    Код (Text):
    1. 00401002 BE FC 20 40 00   mov         esi,4020FCh
    2. 00401007 56               push        esi  
    3. 00401008 E8 97 0A 00 00   call        00401AA4
    4. ...
    5. 00401AA4 FF 25 34 20 40 00 jmp         dword ptr ds:[402034h]
    6. ...
    7. _SetConsoleTitleA@4:
    8. 7C870711 6A 0C            push        0Ch  
    9. 7C870713 68 70 07 87 7C   push        7C870770h
    а вот с __declspec(dllimport) в описании вызов без jmp'а
    Код (Text):
    1. extern "C" __declspec(dllimport) void __stdcall SetConsoleTitleA(const char*);
    Код (Text):
    1. 00401002 BE FC 20 40 00   mov         esi,4020FCh
    2. 00401007 56               push        esi  
    3. 00401008 FF 15 34 20 40 00 call        dword ptr ds:[402034h]
    4. ...
    5. _SetConsoleTitleA@4:
    6. 7C870711 6A 0C            push        0Ch  
    7. 7C870713 68 70 07 87 7C   push        7C870770h
     
  5. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    И всё же не ясно такое поведение линкера.
    Простейший код:
    Код (Text):
    1. int main(void) {
    2.     uncompress(0, 0, 0, 0);
    3. }
    В Debug версии всё собирается нормально. В Release zlib1.dll в импорте есть, но из неё не импортируется uncompress, т.е. ничего не импортируется. Как это объяснить?
     
  6. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    Видимо дело в кривом *.lib файле... Заменил этот файл из пакета на свой сгенерированный из *.def и всё заработало. Весьма странно, библиотека популярная, гугль молчит про мою ситуацию.
     
  7. wsd

    wsd New Member

    Публикаций:
    0
    Регистрация:
    8 авг 2007
    Сообщения:
    2.824
    KeSqueer
    библиотеку не смотрел, а там нет условных макров от _DEBUG_ ?
     
  8. KeSqueer

    KeSqueer Сергей

    Публикаций:
    0
    Регистрация:
    19 июл 2007
    Сообщения:
    1.183
    Адрес:
    Москва
    wsd
    Нету.
    После ребилда lib файла всё заработло. Кстати, размер его уменшьился с 38 кБ до 13 кБ, и исчезло предупреждение '.text' sections have different attributes 0xXXXXXXXX или как-то так.