2011-02-02 2 views
0

У меня есть следующий фрагмент кода, и я думаю, что это может вызвать переполнение в функции readlink().Будет ли это причиной переполнения?

pid_t get_pid_from_proc_self() 
{ 
    char buffer[4]; 
    pid_t pid; 

    readlink("/proc/self", buffer, sizeof(buffer)); 

    sscanf(buffer, "%d",(int *)&pid); 

    return pid; 
} 

Поскольку PID составляет 4 байта в Linux, readlink() копирует 32 бита из "/ Proc/я" в target[]. Затем, по моему мнению, дополнительный байт следует использовать для '\0', что делает его 5 байтами.

Также, readlink() автоматически вставляет '\0' в конце, если строка или мне нужно назначить ее последнему байту?

+1

Спасибо для комментариев, ребята! Было очень сложно принять один ответ. Поэтому я просто выбрал ответ пользователя, который первым заметил, что sscanf() будет переполняться. +1 для всех, хотя :) Мне приятно учиться чему-то новому. –

ответ

1

readlink не будет переполняться, потому что он не помещает '\ 0' в конец. Но sscanf будет. Вы должны сделать это:

Вы должны сделать это:

char buf[5]; 
ssizet_t len; 
... 
if ((len = readlink("/proc/self", buf, sizeof(buf)-1)) != -1) 
    buf[len] = '\0'; 
+0

SO '' функция sscanf() 'скопирует PID + '\ 0' в переменную pid и вызывает переполнение. Я прав? –

+1

ну, sscanf не знает, что буфер длится всего 4 символа, поэтому он будет продолжать проходить мимо конца. – tster

+0

Если I 'Nul' завершает завершение строки в 5-м байте, тогда' sscanf() 'будет копировать 4 байта или 5 байтов: PID + '\ 0'? –

2

За примерами показано здесь:

http://pubs.opengroup.org/onlinepubs/009695399/functions/readlink.html

if ((len = readlink("/modules/pass1", buf, sizeof(buf)-1)) != -1) 
    buf[len] = '\0'; 

Edit:

Интересно о:

Поскольку PID составляет 4 байта в Linux, readlink() копирует 32 бита из «/ proc/self» ...

Не возвращаете ли вы строковую версию PID, а не 4-байтовое целое? Не может ли ваша ценность быть до 10 цифр? 5 цифр? (за комментарий о максимальном значении proc значительно меньше максимального значения 4 байта int - спасибо @Karl)

+2

На самом деле, для большинства распространенных значений '/ proc/sys/kernel/pid_max' он будет больше похож на 5-байтовую строку (мой макс - 32768), но +1 для замечения разницы между строкой и int. –

+1

@ Карл - дерьмо Я знал это (один раз), но я думаю, что мой разум превращается в месиво с недостатком использования. +1 вам за очень полезный комментарий. –

3

Нет, это не вызовет переполнения. Он будет читать не более sizeof(buffer) байт, а затем остановится. Он не завершает нулевую строку, поэтому вам придется это сделать. Чтение buffer перед тем, как обеспечить последний байт \0 приведет к неопределенному поведению (это то, что делает ваш вызов sscanf()).

+1

sscanf будет переполняться ... – tster

+1

Вопрос был о 'readlink()'. Я добавил комментарий о чтении строки перед тем, как убедиться, что она была завершена с нулевым именем для решения проблемы 'sscanf', хотя и не явно. Я это сделаю. –

1

readlink() не вызовет переполнение, но это не добавит трейлинг \0 и sscanf() потенциально может повредить плохо (переполнение буфера). На странице справки readlink().

readlink() помещает содержимое символической ссылки на пути в буфере BUF, , который имеет размер BUFSIZ. readlink() делает не добавляет нулевой байт в buf. Он будет обрезать содержимое (до длины символов bufsiz), если буфер слишком мал, чтобы держать все содержимое .

Кроме того, readlink() читает текст ПИД-регулятора, который может быть больше "9999". Использовать только четыре байта для хранения значения PID в тексте недостаточно.

1

Ваше предположение полностью вне базы.sizeof(pid_t), являющийся 4, не означает, что для сохранения десятичной строки, представляющей число, требуется 4 байта. Типичный 16-разрядный pid, такой как 12345, очевидно, занимает 6 байтов для хранения в виде строки, и если Linux настроен на разрешение более чем 32768 процессов, это может быть проще.

Правильный размер буфера для хранения целочисленного типа foo_t в виде десятичной строки: 3*sizeof(foo_t)+2. Если вам все равно, вы можете сделать немного лучше, но я не против тратить несколько байтов на простоту (и очевидную правильность) в источнике.

(Обратите внимание, что я предполагаю, что 8-битные байты, которые требует POSIX, так как ИДП являются концепция POSIX. Если вы хотите, чтобы поддерживать большие байты вы должны адаптировать связанные с использованием CHAR_BIT.)