2012-05-12 3 views
1

У меня есть следующий код:strdup() вызывает EXC_BAD_ACCESS

char *passwordFunc(const char *s) 
{ 
    static char *pw = NULL; 
    if (strlen(s)) { 
     pw = s; 
    } 
    return pw; 
} 

void keyboard_interactive(const char *name, int name_len, const char *instr, int instr_len, 
          int num_prompts, const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, LIBSSH2_USERAUTH_KBDINT_RESPONSE *res, 
          void **abstract) 
{ 
    char *text = passwordFunc(""); 
    res[0].text = strdup(text); 
    res[0].length = strlen(text); 
} 

Согласно отладчика, каждый раз, когда он попадает в линию с strdup(text), он падает с EXC_BAD_ACCESS (code=2, address=0x0).

Любые предложения относительно того, что происходит и как его исправить? Заранее спасибо.

+1

Какова цель вашего 'passwordFunc' функции? Для любой непустой строки она возвращает свой аргумент; для пустой строки он возвращает нулевой указатель. Это не кажется полезным. Что делать, если вы просто просто отключите функцию passwordFunc и измените первое объявление в 'keyboard_interactive' на' char * text = ""; '? –

+0

Является ли 'res' действительным указателем для записи? –

+0

Как я могу проверить это? 'keyboard_interactive' является обратным вызовом libssh2, поэтому я не понимаю, почему это было бы неверно. –

ответ

4

passwordFunc("") возвращается NULL. Когда вы передаете это значение strdup, вы получаете ошибку сегментации, потому что strdup ожидает действительную строку C. То, что сообщение об ошибке относится к адресу 0x0, указывает на то, что программа отменяет ссылку на нулевой указатель.

Теперь passwordFunc("") возвращает NULL, потому что strlen("") равно нулю, а ноль оценивается как ложное.

Некоторые реализации strdup возвращают пустую строку при ее передаче NULL. Кажется, что этот код был написан, предполагая такую ​​реализацию. Библиотека вашего компилятора ведет себя по-разному.

Возможно, вы можете исправить код наиболее легко, предоставив свою собственную реализацию strdup, которая ведет себя так, как предполагает этот код.

char *strdup(const char *s) { 
    size_t len = (s == NULL) ? 1 : strlen(s) + 1; 
    char *result = malloc(len); 
    if (result != NULL) 
     if (len>1) 
      memcpy(result, s, len);      
     else 
      *result = 0; 
    return result;       
} 

Как и в сторону, я бы прокомментировать, что passwordFunc должен действительно вернуться const char*, а не char* и также pw должны быть const char*. Возможно, ваш компилятор предупреждает вас об этом, и вы должны прислушаться к этим предупреждениям.

+0

@ Keith Thompson и David Heffernan Я не совсем уверен, что делает сама функция. Файл является оберткой на libssh2. Весь файл находится здесь: https://github.com/gonzopancho/libssh2-for-iOS/blob/74f58c146c9556789c9297a9c7d8a3818472cabf/Classes/SSHWrapper.m. Я не могу изменить аргументы на keyboard_interactive, потому что эта функция является обратным вызовом в libssh2 для входа в интерактивный режим. Мое лучшее предположение о том, что происходит в passwordFunc, заключается в том, что он называется ранее, чтобы сохранить пароль в статическом var, а затем вызвал в keyboard_interactive для его получения. –

+0

Я добавил NSLog для регистрации строки пароля, возвращаемой passwordFunc, и это был правильный пароль, так может ли это быть 'res [0] .text' part? –

+3

'strdup (NULL)' является ошибкой. Вот и все. –

0

Ваша проблема в том, что функция обратного вызова иногда вызывается, даже если не было приглашения. Поэтому вам нужно убедиться, что вам нужно установить что-то на объекте res.

Этот фрагмент кода будет решить вашу проблему:

void keyboard_interactive(const char *name, int name_len, const char *instr, int instr_len, 
          int num_prompts, const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts, LIBSSH2_USERAUTH_KBDINT_RESPONSE *res, 
          void **abstract) 
{ 
    if(num_prompts > 0) { 
     res[0].text = strdup(passwordFunc("")); 
     res[0].length = strlen(passwordFunc("")); 
    } 
}