avva: (Default)
[personal profile] avva
(интересно только программистам, знающим C)

Майкрософтовский strlen(), оказывается, не проверяет, не передали ли ему случаем NULL, а по-простому читает то, что по переданному адресу находится, и падает кверху лапками.

Если майкрософтовскому printf'у передать NULL в качестве аргумента, соответствующего %s в строке формата, он это проверит и выдаст "(null)".

Однако у Glib'а (библиотека низкого уровня, лежащая в основе GTK, в основном использующаяся на юниксах, но по идее поддерживающая и платформу Win32) есть внутри своя имплементация printf'а (а точнее, vasnprintf()'а, чтобы покрыть все возможные случаи). Она не делает полностью всю работу printf'а, а всего лишь обрабатывает строку формата и аргументы и строит отдельные более простые вызовы snprintf/sprintf (хотя бы sprintf уже должен быть везде) для каждого аргумента, размещая их по очереди в буфере возврата. Glib использует эту имплементацию в том случае, когда у платформы, на которой её строят, нет своего достаточно хорошего и поддерживающего всё, что нужно, printf'а. Win32 - одна из таких платформ.

Если этому внутреннему Glib'овскому printf'у передать NULL в качестве аргумента, соответствующего %s в форматной строке, то он в определённый момент вызовет strlen() на этот аргумент, чтобы узнать длину строки аргумента - для того, чтобы создать буфер достаточной длины. Увы, авторам этого printf'а не пришло в голову, что strlen на какой-то платформе может упасть, если передать ему NULL. Поэтому они это не проверяют, и в результате, если вызвать что-то вроде: g_printf("foo: %s\n", NULL), то программа упадёт.

Это всё я обнаружил, пытаясь построить и заставить что-то делать ЖЖ-клиент LogJam под Windows XP.

Интересно, кто виноват? Аппликация, передающая какой-либо версии printf'а аргумент NULL для подстановки к %s? Имплементация printf'а, вызывающая strlen(), не проверяя аргумент на ==NULL? Имплементация strlen(), идущая сразу по адресу аргумента, не проверяя на NULL?

P.S. Проверил strlen() на юниксах (glibc). Он тоже, оказывается, не проверяет на NULL. Но там тот же баг не проявлялся потому, что GLib использует системный printf, а не свой, а системный это дело проверяет.

Date: 2005-03-27 11:07 am (UTC)
From: [identity profile] avva.livejournal.com
В POSIX'овском определении этих функций ничего такого не написано.

Date: 2005-03-27 12:42 pm (UTC)
From: [identity profile] michk.livejournal.com
А разве это не предполагается по умолчанию в C? Мне всегда казалось, что ни одна функция не обязана проверять на NULL, а если кто-то проверяет, то это "подарок", и никак не стандарт.

Date: 2005-03-27 02:12 pm (UTC)
From: [identity profile] arbat.livejournal.com
это не подарок, а нарушение стандарта :-)

Date: 2005-04-05 05:58 pm (UTC)
From: [identity profile] lazyreader.livejournal.com
Неопределённое поведение не может нарушить стандарт по определению :)

Date: 2005-03-27 01:52 pm (UTC)
From: [identity profile] gdy.livejournal.com
C99 7.1.4
Each of the following statements applies unless explicitly stated otherwise in the detailed
descriptions that follow: If an argument to a function has an invalid value (such as a value
outside the domain of the function, or a pointer outside the address space of the program,
or a null pointer, or a pointer to non-modifiable storage when the corresponding
parameter is not const-qualified) or a type (after promotion) not expected by a function
with variable number of arguments, the behavior is undefined. If a function argument is
described as being an array, the pointer actually passed to the function shall have a value
such that all address computations and accesses to objects (that would be valid if the
pointer did point to the first element of such an array) are in fact valid.

В 7.9.6.1 (fprintf) ничего про NULL не видно

Date: 2005-03-27 02:02 pm (UTC)
From: [identity profile] gdy.livejournal.com
А posix это повторяет
Each of the following statements shall apply unless explicitly stated otherwise in the detailed descriptions that follow:
  1. If an argument to a function has an invalid value (such as a value outside the domain of the function, or a pointer outside the address space of the program, or a null pointer), the behavior is undefined.

Date: 2005-03-27 02:07 pm (UTC)
From: [identity profile] avva.livejournal.com
Да, спасибо, я тоже уже эту цитату нашёл в каком-то споре по этому поводу сетевом. Но всё равно спасибо ;)

Date: 2005-03-27 08:16 pm (UTC)
From: [identity profile] dvv.livejournal.com
А не проще цитаты из стандарта искать в стандарте, а не в каких–то спорах?

Date: 2005-03-27 08:28 pm (UTC)
From: [identity profile] avva.livejournal.com
У меня нет своей копии C99, она мне не нужна.

Date: 2005-03-27 08:47 pm (UTC)
From: [identity profile] dvv.livejournal.com
Эта дискуссия — верный признак того, что нужна. Собственно, копия стандарта языка должна быть под рукой у любого программиста, профессионально с языком работающего.

January 2026

S M T W T F S
    1 2 3
4 5678910
11121314151617
18192021222324
25262728293031

Most Popular Tags

Style Credit

Expand Cut Tags

No cut tags
Page generated Jan. 6th, 2026 01:38 am
Powered by Dreamwidth Studios