2016-12-11 5 views
0

Я пытаюсь написать простой драйвер устройства и прикладную программу для доступа к драйверу.ошибка сегментации при использовании sprintf

Драйвер системы записи вызова выглядит эта программа

static ssize_t dev_write(struct file *filp, const char *buff, size_t len, loff_t *off) 
{ 
short c=0; 
short ind =0; 
short count=0; 
memset(msg,0,100); 
readPos=0; 
while(len>0) 
{ 
msg[count++]=buff[ind++]; 
len--; 
} 

и приложение, которое работает выглядит следующим образом

int main() 
{ 
char buf[100]; 
char i = 0; 
char tag=0; 

int fp; 
char *val[10]; 
char *rval[10]; 
unsigned int a =18440; 
unsigned int d =1; 
memset(buf, 0, 10); 
tag=1; 
fp = open("/dev/dd",O_RDWR); 
if (fp<0) 
{ 
    printf("file failed to open\n"); 
} 
sprintf(val[1],"%d%x%x",tag,a,d); 
write(fp,val[1],strlen(val[1])); 
sprintf(rval[1],"%d%x",tag,a);// statement that causes segmentation fault 
return 0; 
} 

Теперь, если я добавлю еще одну функцию Sprintf, как показано выше, это приводит к сегментации вины .Я не знаю почему?. Если я удалю эту строку, код будет работать нормально. В чем может быть проблема? Та же проблема возникает, когда я вызываю sprintf и записываю как вызов подфункции?

+2

Где находится 'msg'? Что это? Была ли сделана компиляция с включенными предупреждениями? Любые предупреждения? – chux

+2

'val [1]', 'char *', присваивается 'sprintf()' без присвоенного ему значения. 'sprintf (val [1],"% d% x% x ", tag, a, d);' получает указатель на мусор. – chux

+0

'char * val [10]; char * rval [10]; '->' char val [24]; char rval [24]; ',' snprintf (val, sizeof (val), "% d% x% x", tag, a, г) и т. д. – BLUEPIXY

ответ

1

Учитывая заданный вопрос и значительные проблемы, обнаруженные в другом месте в коде, я полагаю, что вы программист для начинающих C и, возможно, начинающий программист в целом. Поэтому я настоятельно рекомендую вам не играть с внутренними компонентами ядра. Намного проще писать и отлаживать содержимое пользовательского пространства.

Я также должен отметить, что комментарии, которые могут быть найдены ниже вопроса, мне свойственны тем, что они касаются исключительно незначительных точек, игнорируя общую картину.

Сначала я обработаю часть пользовательского пространства, а затем прокомментирую код ядра.

int main() 
{ 
char buf[100]; 

В вашем фактическом коде код функции также начинается в начале строки? Обычно люди отступают не менее чем на 4 пробела, если не 8. Или вкладка в этом отношении.

char i = 0; 

Неиспользованная переменная.

char tag=0; 

Почему здесь установлено 0 и почему стиль отличается от вышеуказанной строки? ("=" vs "")

int fp; 

Файловые дескрипторы обычно называются «fd». 'fp' используется для вещей, возвращаемых, например, Еореп.

char *val[10]; 
char *rval[10]; 
unsigned int a =18440; 
unsigned int d =1; 

Еще один стиль назначения.

memset(buf, 0, 10); 

Почему?

tag=1; 

Это перезаписывает присвоение в декларации.

fp = open("/dev/dd",O_RDWR); 
if (fp<0) 
{ 
    printf("file failed to open\n"); 

Это должно печатать фактическую полученную ошибку, например. с ужасом. Также обратите внимание, что программа продолжает выполнение, несмотря на ошибку.

} 
sprintf(val[1],"%d%x%x",tag,a,d); 

Как было правильно отмечено в одном из комментариев, значение Валу [1] не определен и письменной форме, что это неопределенное поведение. Учитывая серьезность проблемы, я думаю, вам нужно перечитать уроки о указателях и обработке строк.

write(fp,val[1],strlen(val[1])); 

StrLen легко избежать путем захвата возвращаемого значения Sprintf вместо

sprintf(rval[1],"%d%x",tag,a);// statement that causes segmentation fault 

Той же проблемы, как и в предыдущем Sprintf.

return 0; 
} 

Теперь часть ядра. Пока вставленный образец неполный, достаточно заметить, что модуль ошибочен.

static ssize_t dev_write(struct file *filp, const char *buff, size_t len, loff_t *off) 
{ 
short c=0; 
short ind =0; 
short count=0; 

Почему эти типы короткие? Это проблема, о которой говорилось ниже. Также почему вы устанавливаете их здесь 0?

memset(msg,0,100); 

Почему memset даже выполнен?

Неизвестно, что такое msg, но повторные 100 сильно намекают на неправильный код. Если это статический буфер, следует использовать sizeof (msg). В противном случае должен быть макрос или переменная с размером.

readPos=0; 

Это, скорее всего, неверно.

while(len>0) 

len не был проверен относительно размера буфера, поэтому, в частности, вы можете начать писать через буфер. Также отметим, как имеющий специальный способ выражения размера буфера позволило бы избежать повторения другого числа 100.

{ 
msg[count++]=buff[ind++]; 

Len имеет тип size_t, который значительно длиннее, чем короткие, который используется как для подсчета и Ind есть. Таким образом, в деталях для размеров, больших, чем у представимых с положительным знаком, это будет практически переворачиваться с + 32k до -32k. То есть, вы начнете писать материал до в буфер. Если это произойдет, чтобы не сбой, вы повторите цикл, предоставленный достаточно большой len.

Но это действительно второстепенный момент, поскольку доступ к буферу пользовательского пространства выполняется неправильно. Цитировать себя из других источников: Доступ к этому способу - это угроза безопасности и надежности. Рассмотрите, что происходит, когда пользователь передает адрес чего-либо внутри ядра или является мусором. Также он будет работать неправильно в нескольких случаях (например, SMAP или архитектуры, у которых пространство адресов ядра разделено на пространство пользователей).

Вам нужно get_user, copy_from_user или подобное.

len--; 
}