Pull to refresh

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

Reading time 2 min
Views 15K
Идея в следующем. Чтобы не было разыменования нулевого указателя, нужно, чтобы не было нулевого указателя. Ваш КО. Так сложилось, что однажды я исправил небольшую проблему в ядре Linux, но это была не текущая ветка ядра, а стабильная. В текущей, на тот момент, эту проблему тоже исправили, но по другому.

Проблема была простая и весьма распространенная. Один поток освобождает буфер, во время, пока второй продолжает его использовать. Состояние гонки. Как избежать этой ситуации? Можно заставить один поток подождать, пока второй использует буфер, решение простое, но не эффективное, порой громоздкое.

Первый вариант

Мое решение было другим, а зачем, собственно ждать, пока освободиться буфер, чтобы тут же его стереть? Давайте оставим его в покое, буфер небольшой 512 байт погоды не сделает. Удалим все другие буферы, которые точно в данный момент не используются, а последний оставим. Это намного облегчит процесс синхронизации двух потоков ядра, об этом просто не надо будет думать. А данные, которые останутся в буфере, в любом случае могут быть, т.к. поступают туда по прерыванию, и даже, если бы мы освободили последний буфер, в тот же момент, по прерыванию, возможно выделение нового буфера и запись туда новых данных. Таким образом, получаем эффективное и более простое решение, чем решение в лоб. Пришлось удалять первое исправление и добавлять свое, что сделало исправление намного больше, чем должно было быть.

Второй вариант
Первоначальный вариант.
---
diff --git a/drivers/tty/tty_buffer.c b/drivers/tty/tty_buffer.c
index 6c9b7cd..4f02f9c 100644
--- a/drivers/tty/tty_buffer.c
+++ b/drivers/tty/tty_buffer.c
@@ -114,11 +114,14 @@ static void __tty_buffer_flush(struct tty_struct *tty)
 {
 	struct tty_buffer *thead;
 
-	while ((thead = tty->buf.head) != NULL) {
-		tty->buf.head = thead->next;
-		tty_buffer_free(tty, thead);
+	if (tty->buf.head == NULL)
+		return;
+	while ((thead = tty->buf.head->next) != NULL) {
+		tty_buffer_free(tty, tty->buf.head);
+		tty->buf.head = thead;
 	}
-	tty->buf.tail = NULL;
+	WARN_ON(tty->buf.head != tty->buf.tail);
+	tty->buf.head->read = tty->buf.head->commit;
 }
 
 /**

Чтобы убрать «if», хорошо бы первый буфер выделять при открытии файла устройства, а не когда появятся первые данные, но это, усложнило бы «patch».

Мое мнение о разработке ядра Linux
Хорошо латать дыры первым попавшимся методом или плохо? Мне кажется что плохо, сам процесс внесения изменений в ядро выглядит, как какая-то гонка, кто успел тот и внес изменения, а последствия, потом разберемся. Мне кажется, что таких исправлений в ядро попадает слишком много, что еще больше запутывает и так не простой код.
Tags:
Hubs:
+16
Comments 17
Comments Comments 17

Articles