LINUX.ORG.RU

Навеяно свежей дырой в Xorg

 , ,


9

7

Привет, ЛОР!

Ты, наверное, уже видел свежую дыру в Xorg, патч для которой выглядит буквально вот так:

-        else
+        else {
             free(to->button->xkb_acts);
+            to->button->xkb_acts = NULL;
+        }

В связи с этим у меня возник вопрос: а почему в стандартной библиотеке C нет макроса SAFE_FREE()?

#define SAFE_FREE(ptr) do{free(ptr);(ptr)=NULL;}while(0)

Напомню, что значение указателя после вызова free() является неопределённым согласно стандарту. Не только значение памяти, на которое он указывает, но и значение самого указателя, и работа с ним представляет собой жуткое undefined behaviour, а значит единственное что можно сделать – занулить его.

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

Моя гипотеза тут: C – это язык культа страданий во имя страданий.

Ответ на: комментарий от hateyoufeel

Компилятор без проблем может выкинуть этот printf(), например. Или вообще всю программу. И это не будет багом.

printf не пытается извлечь то, что хранится по указанному адресу. он даже не знает - адрес ли это. он просто выводит переданное ему значение в указанном ему формате.

#include <stdio.h>
#include <stdlib.h>

int main(void){

    int *j = malloc(sizeof(int));
    printf("%p %d\n", j, j[0]); // ok
    free(j);
    printf("%p\n", j); // ok

    printf("%p %d\n", j, j[0]); // UB

    return 0;
}

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

olelookoe ★★★
()
Ответ на: комментарий от olelookoe

printf не пытается извлечь то, что хранится по указанному адресу. он даже не знает - адрес ли это. он просто выводит переданное ему значение в указанном ему формате.

И ты тоже перечитай цитату из стандарта ещё раз. Использование самого значения является UB.

UB возникает тогда, когда мы действуем, а не тогда, когда храним.

UB возникает, когда ты пишешь говнокод, а компилятор пытается его скомпилировать. Ещё раз, в C этот термин означает буквально следующее: если нарушены следующие условия (в данном случае, использование значения указателя после вызова free()), то поведение программы не определено и может быть любым.

hateyoufeel ★★★★★
() автор топика
Последнее исправление: hateyoufeel (всего исправлений: 2)
Ответ на: комментарий от olelookoe

UB возникает тогда, когда мы действуем

UB возникает тогда, когда стандарт говорит, что возникает UB.

cumvillain
()
Ответ на: комментарий от olelookoe

Компилятор выдаст тебе говно вместо работающей программы. Что непонятного-то?

Ты можешь писать вообще что угодно, хоть *NULL. Но это не будет корректной программой на языке C.

hateyoufeel ★★★★★
() автор топика
Последнее исправление: hateyoufeel (всего исправлений: 1)
Ответ на: комментарий от olelookoe

а присвоить указателю произвольное значение мы можем?

Сегодня у нас, видимо, публичные чтения стандарта:

An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.

cumvillain
()
Ответ на: комментарий от cumvillain

вопрос вот в чем

#include <stdio.h>
#include <stdlib.h>

int main(void){

    int *ptr = (int*) 0xDEADBEEF;

    printf("%p\n", 0xDEADBEEF); // так можно
    printf("%p\n", ptr); // а так уже нельзя?

    ptr = malloc(sizeof(int));
    free(ptr);
    printf("%p\n", ptr); // а так вапще низя никада!

    return 0;
}

да?)

olelookoe ★★★
()
Ответ на: комментарий от olelookoe
printf("%p\n", 0xDEADBEEF); // так можно

нет, нельзя :D

fail.c: In function ‘main’:
fail.c:8:14: warning: format ‘%p’ expects argument of type ‘void *’, but argument 2 has type ‘unsigned int’ [-Wformat=]
    8 |     printf("%p\n", 0xDEADBEEF); // так можно
      |             ~^     ~~~~~~~~~~
      |              |     |
      |              |     unsigned int
      |              void *
      |             %d
cumvillain
()
Ответ на: комментарий от cumvillain
#include <stdio.h>
#include <stdlib.h>

int main(void){

    int *ptr = (int*) 0xDEADBEEF;

    printf("%p\n", (void*) 0xDEADBEEF); // так можно
    printf("%p\n", ptr); // а так уже нельзя?

    ptr = malloc(sizeof(int));
    free(ptr);
    printf("%p\n", ptr); // а так вапще низя никада!

    return 0;
}

пойдет? )

olelookoe ★★★
()
Ответ на: комментарий от olelookoe
int *ptr = (int*) 0xDEADBEEF;

Согласно стандарту, тут implementation defined.

(void*) 0xDEADBEEF

Как и тут.

printf("%p\n", ptr); // а так уже нельзя?

Можно, если ptr, который ты получил кастом, валидный.

printf("%p\n", ptr); // а так вапще низя никада!

Согласно стандарту, нельзя.

cumvillain
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.