LINUX.ORG.RU

На какую область памяти ссылается указатель (Си)

 ,


1

3

Как проверить, сделан ли к текущему моменту free(buf), или же область памяти на которую указывает buf доступна для read-write приложением?

int main() {
	const uint64_t N = 2;
	uint8_t *a = (uint8_t *)calloc(1,N);
	/* 32-битный адрес; --std=c99 -O0 -march=i386 */
	printf("a=0x%08X\n",(uint32_t)a);
	free(a);
	printf("a=0x%08X\n",(uint32_t)a);
        ...
★★★★★

просто не обращайся к этому указателю после free()

алсо. говнокодеров переписи тред (каменты выше)

anonymous
()

<TroolMode> Дерни free. Если упадет по двойному освобождению то... ну ты понял. </TroolMode>

exception13 ★★★★★
()

С какой целью интересуетесь? Если для тестирования и поиска проблем, то можно подменить malloc и free и вести учёт выделенных и освобождённых блоков, если это зачем-то в реальном коде понадобилось, то ты делаешь что-то странное.

Gvidon ★★★★
()

пляши от

8.7 Example - A Storage Allocator (page 173 in chapter 8: The Unix System Interface ) from

The C Programming Language.1978 by Bell Telephone Laboratities,Inc.

qulinxao ★★☆
()

мелкий фикс:

printf("a=0x%08X\n",-1[(uint32_t *)a]);
free(a);
printf("a=0x%08X\n",-1[(uint32_t *)a]);
опираясь на результат можно с некоторой надёжностью выяснять освобождён-ли a

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

и разве не яснее?:

void __pfcq_free(void** _pointer)
{
	if (!likely(_pointer))return;
	
	void* p = *_pointer;
	if (!likely(p))return;

	size_t* s = (size_t*)p - 1;
	if (!likely(s))return;

	size_t size = *s;
	pfcq_zero(s, size);
	free(s);
	*_pointer = NULL;

}

ps. какой нить претипринтер позволяет такие синтаксические эквивалентые преобразования(в обе стороны) а?

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

какой нить претипринтер позволяет такие синтаксические эквивалентые преобразования(в обе стороны) а?

Присоединяюсь к вопросу.

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

а уж если семантику

аха

#define likely(x)	   	__builtin_expect(!!(x), 1) 
то


void __pfcq_free(void** _pointer)
{
	if (unlikely(_pointer))return;
	
	void* p = *_pointer;
	if (unlikely(p))return;

	size_t* s = (size_t*)p - 1;
	if (unlikely(s))return;

	size_t size = *s;
	pfcq_zero(s, size);
	free(s);
	*_pointer = NULL;

}
qulinxao ★★☆
()
Последнее исправление: qulinxao (всего исправлений: 1)

область памяти на которую указывает buf доступна для read-write приложением?

На уровне станичной защиты можно такой хак провернуть:

1. Делаешь fork().

В отфоркнутом процессе:
2. устанавливаешь сигхэндлер на sigsegv, чтобы делал _exit() с заранее указанным кодом возврата
3. указываешь сигхэндлеру код возврата 2
4. читаешь байт по интересующему адресу
5. указываешь сигхэндлеру код возврата 1
6. пишешь этот же байт по этому же адресу
7. делаешь _exit(0)

В исходном процессе:
2. делаешь waitpid
3. анализируешь код возврата: 0 - rw, 1 - read-only, 2 - no read

Но к malloc/free это прямого отношения не имеет

Manhunt ★★★★★
()

Как проверить, сделан ли к текущему моменту free(buf)

Можно завести хэш-табличку с доступными для free() адресами, и заполнять её из http://www.gnu.org/software/libc/manual/html_node/Hooks-for-Malloc.html

Проверкой будет lookup в этой таблице.

Manhunt ★★★★★
()
Последнее исправление: Manhunt (всего исправлений: 1)

Ну а в целом, ты делаешь что-то чрезвычайно странное (и с вероятностью 99.9999999% ублюдочное), если тебе необходимы такие проверки.

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

и уж если уж

void __pfcq_free(void** _pointer)
{
	void* p;
	size_t* s; 
	if(  unlikely(_pointer)
           ||unlikely(p=*_pointer)
           ||unlikely(s= (size_t*)p - 1)
        )return;

	size_t size = *s;
	pfcq_zero(s, size);
	free(s);
	*_pointer = NULL;

}

:)!

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

Ну а в целом, ты делаешь что-то чрезвычайно странное

Просто я хотел написать красивый код. Начал делать дампы RETURN VALUEs и проч.переменных, и понял что free(buf) оставляет buf неизменным. И сразу же возник вопрос - можно ли получить доступ к карте памяти процесса.

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

понял что free(buf) оставляет buf неизменным

В обнулении переменной buf нет смысла, потому что ты её значение (то есть полученный от malloc адрес) мог скопировать в другие переменные.

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

доступ к карте памяти процесса

Если procfs смонтирован, то есть такая карта:

 $ cat /proc/$$/maps
00400000-0049c000 r-xp 00000000 08:02 15466666 /bin/bash
0069b000-0069c000 r--p 0009b000 08:02 15466666 /bin/bash
0069c000-006a0000 rw-p 0009c000 08:02 15466666 /bin/bash
006a0000-006ab000 rw-p 00000000 00:00 0
01a21000-01c41000 rw-p 00000000 00:00 0 [heap]
7f831ddca000-7f831ddcc000 r-xp 00000000 08:02 28707298 /usr/lib64/gconv/KOI8-R.so
7f831ddcc000-7f831dfcb000 ---p 00002000 08:02 28707298 /usr/lib64/gconv/KOI8-R.so
7f831dfcb000-7f831dfcc000 r--p 00001000 08:02 28707298 /usr/lib64/gconv/KOI8-R.so
7f831dfcc000-7f831dfcd000 rw-p 00002000 08:02 28707298 /usr/lib64/gconv/KOI8-R.so
7f831dfcd000-7f831e16b000 r-xp 00000000 08:02 20185166 /lib64/libc-2.19.so
7f831e16b000-7f831e36a000 ---p 0019e000 08:02 20185166 /lib64/libc-2.19.so
7f831e36a000-7f831e36e000 r--p 0019d000 08:02 20185166 /lib64/libc-2.19.so
7f831e36e000-7f831e370000 rw-p 001a1000 08:02 20185166 /lib64/libc-2.19.so
7f831e370000-7f831e374000 rw-p 00000000 00:00 0
7f831e374000-7f831e377000 r-xp 00000000 08:02 20185181 /lib64/libdl-2.19.so
7f831e377000-7f831e576000 ---p 00003000 08:02 20185181 /lib64/libdl-2.19.so
7f831e576000-7f831e577000 r--p 00002000 08:02 20185181 /lib64/libdl-2.19.so
7f831e577000-7f831e578000 rw-p 00003000 08:02 20185181 /lib64/libdl-2.19.so
7f831e578000-7f831e5a3000 r-xp 00000000 08:02 20185269 /lib64/libtinfo.so.5.9
7f831e5a3000-7f831e7a2000 ---p 0002b000 08:02 20185269 /lib64/libtinfo.so.5.9
7f831e7a2000-7f831e7a6000 r--p 0002a000 08:02 20185269 /lib64/libtinfo.so.5.9
7f831e7a6000-7f831e7ab000 rw-p 0002e000 08:02 20185269 /lib64/libtinfo.so.5.9
7f831e7ab000-7f831e7ac000 rw-p 00000000 00:00 0
7f831e7ac000-7f831e7ea000 r-xp 00000000 08:02 20185117 /lib64/libreadline.so.6.2
7f831e7ea000-7f831e9ea000 ---p 0003e000 08:02 20185117 /lib64/libreadline.so.6.2
7f831e9ea000-7f831e9ec000 r--p 0003e000 08:02 20185117 /lib64/libreadline.so.6.2
7f831e9ec000-7f831e9f2000 rw-p 00040000 08:02 20185117 /lib64/libreadline.so.6.2
7f831e9f2000-7f831e9f4000 rw-p 00000000 00:00 0
7f831e9f4000-7f831ea14000 r-xp 00000000 08:02 20185096 /lib64/ld-2.19.so
7f831ea49000-7f831ea7e000 r--s 00000000 00:11 13675 /run/nscd/passwd
7f831ea7e000-7f831eabd000 r--p 00000000 08:02 28185994 /usr/lib/locale/ru_RU.utf8/LC_CTYPE
7f831eabd000-7f831ebed000 r--p 00000000 08:02 28315109 /usr/lib/locale/ru_RU.utf8/LC_COLLATE
7f831ebed000-7f831ebf1000 rw-p 00000000 00:00 0
7f831ebfd000-7f831ebff000 rw-p 00000000 00:00 0
7f831ebff000-7f831ec02000 r--p 00000000 08:02 28846490 /usr/share/locale-bundle/ru/LC_MESSAGES/bash.mo
7f831ec02000-7f831ec03000 r--p 00000000 08:02 28315304 /usr/lib/locale/ru_RU.utf8/LC_NUMERIC
7f831ec03000-7f831ec04000 r--p 00000000 08:02 28185982 /usr/lib/locale/ru_RU.utf8/LC_TIME
7f831ec04000-7f831ec05000 r--p 00000000 08:02 28185981 /usr/lib/locale/ru_RU.utf8/LC_MONETARY
7f831ec05000-7f831ec06000 r--p 00000000 08:02 28315664 /usr/lib/locale/ru_RU.utf8/LC_MESSAGES/SYS_LC_MESSAGES
7f831ec06000-7f831ec07000 r--p 00000000 08:02 28185999 /usr/lib/locale/ru_RU.utf8/LC_PAPER
7f831ec07000-7f831ec08000 r--p 00000000 08:02 28312321 /usr/lib/locale/ru_RU.utf8/LC_NAME
7f831ec08000-7f831ec09000 r--p 00000000 08:02 28181315 /usr/lib/locale/ru_RU.utf8/LC_ADDRESS
7f831ec09000-7f831ec0a000 r--p 00000000 08:02 28181302 /usr/lib/locale/ru_RU.utf8/LC_TELEPHONE
7f831ec0a000-7f831ec0b000 r--p 00000000 08:02 28185995 /usr/lib/locale/ru_RU.utf8/LC_MEASUREMENT
7f831ec0b000-7f831ec12000 r--s 00000000 08:02 28709428 /usr/lib64/gconv/gconv-modules.cache
7f831ec12000-7f831ec13000 r--p 00000000 08:02 28185980 /usr/lib/locale/ru_RU.utf8/LC_IDENTIFICATION
7f831ec13000-7f831ec14000 rw-p 00000000 00:00 0
7f831ec14000-7f831ec15000 r--p 00020000 08:02 20185096 /lib64/ld-2.19.so
7f831ec15000-7f831ec16000 rw-p 00021000 08:02 20185096 /lib64/ld-2.19.so
7f831ec16000-7f831ec17000 rw-p 00000000 00:00 0
7fff1ac46000-7fff1ac67000 rw-p 00000000 00:00 0 [stack]
7fff1ad80000-7fff1ad82000 r-xp 00000000 00:00 0 [vdso]
7fff1ad82000-7fff1ad84000 r--p 00000000 00:00 0 [vvar]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]

Manhunt ★★★★★
()

Как проверить, сделан ли к текущему моменту free(buf)

Никак.

или же область памяти на которую указывает buf доступна для read-write приложением?

Это как-бы не одно и тоже. free освобождает память из libc, это не значит, память теперь недоступна процессу и в неё нельзя писать.

no-such-file ★★★★★
()
Ответ на: комментарий от no-such-file

это не значит, память теперь недоступна процессу и в неё нельзя писать.

Однако это значит, что запись в неё влечёт UB.

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

Как и чтение. Любая попытка как-то провзаимодействовать с этой памятью.

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

Чтобы проверить принадлежность адресному пространству, немного проще использовать read(2)/write(2) и анализировать ошибки.

anonymous
()
Ответ на: комментарий от i-rinat

Не, теперь буду знать. Чего только в GNU не понапридумывали.

post-factum ★★★★★
()
Ответ на: комментарий от Waterlaz

nalojil pf-kernel na yadro freebsd I volosi stali myagkimi I shelkovistimi.

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

Нет, посмотри внимательнее, оно обёрнуто в #ifdef __GNUC__. __builtin_expect — это чисто гнутая штука, и если гнутые расширения недоступны, макрос превращается в пустышку.

post-factum ★★★★★
()
Ответ на: комментарий от Nietzsche

#define FREE(p) do { free(p); (p) = NULL; } while(0)

отличный код, бро !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!111 только вот у меня почему-то FREE(string_array[++ptr]) как-то очень странно работает... и FREE(string_array[ptr++]) тоже...

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

Вполне типичный макрос:

#define MAX(a, b) ((a) > (b) ? (a) : (b))
страдает от тех же недугов, тем не менее - пользуются же.

Если нет желания юзать инлайны, то gcc для таких целей припас костылей.

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

тем не менее - пользуются же.

ты только не сказал главное — кто пользуются?

мазохисты могут продолжать пользоваться макросами вместо inline-функций

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

если уж прямо совсем не хочется пользоваться с++ в виде «си с референсами», то можно хотя бы такой костыль сделать:

void my_free(void** ptr_to_ptr)
{
  free(*ptr_to_ptr);
  *ptr_to_ptr = NULL;
}

#define FREE(ptr) my_free(&(ptr))

есть какие-либо способы сломать этот макрос? (но во всяком случае он уже прочнее того, что ты написал)

www_linux_org_ru ★★★★★
()
Ответ на: комментарий от Waterlaz
do {..} while(0)

Поясни, зачем while(0)? Он же не пойдёт на очередной цикл. Проще сделать так:

{..}
если речь о локализации переменных.

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

Добавлю ещё, что кастовать calloc/malloc больше не надо. Раньше случалось, теперь уже нет. Но гомнокнижки ещё не переписали. ;)

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

Если сделать так, как ты говоришь, то ... не скомпилируется.

А ты убери точку с запятой после if(..) FREE(p)

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

А ты убери точку с запятой после if(..) FREE(p)

Нехер мне делать. Конструкция do { } while(0) работает так, как надо.

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