Skip to content

Instantly share code, notes, and snippets.

@zamabuvaraeu
Last active June 17, 2026 03:16
Show Gist options
  • Select an option

  • Save zamabuvaraeu/a7f6bd1688268a459358203f8d9373da to your computer and use it in GitHub Desktop.

Select an option

Save zamabuvaraeu/a7f6bd1688268a459358203f8d9373da to your computer and use it in GitHub Desktop.
Подводные камни передачи буфера в функцию

Подводные камни передачи буфера в функцию

Пусть ваша DLL экспортирует такую функцию:

Function Foo( _
		ByVal Buffer As WString Ptr, _
		ByVal Length As Integer _
	)As Boolean

	' Что‐то делаем:
	Dim res As Boolean = Initialize(...)
	If res = False Then
		Return False
	End If

	' Работаем с буфером
	write(Bufer, Length, ...)

	Return True

End Function

Соглашение по вызову просто: функция вернула True — значит, она завершилась успешно и вы можете использовать данные в Buffer. Если же функция вернула False, то она завершилась ошибкой, и значение Buffer не определено. Казалось бы, простое и логичное правило: что тут может пойти не так?

Дело в том, что проверять результат работы функции — это же куча работы. Люди ленивы. Поэтому они могут заметить, что ваша функция не трогает буфер, если она завершается неудачей. И они могут написать код вроде такого:

var buf = CAllocate(Length)

' Вызываем функцию из DLL
Foo(buf, Length)

' Выводим результат
PrintBuffer(buf, Length)

' Очистка
Deallocate(buf)

В этом куске кода подразумевается, что если функция Foo завершится неудачно, то в buf будут нули, ведь он не тронут. Нули — это допустимое значение для нуль-терминированных строк, поэтому мы просто продолжаем выполнение (функция PrintBuffer).

Но нигде в контракте функции Foo об этом не сказано, поэтому это — деталь реализации. И однажды в новой версии DLL (и функции Foo) вы используете буфер buf для промежуточных вычислений. Вам нужен кусок памяти, и тут как раз он без дела болтается, так что вы используете его. Вы имеете полное право на это, вы всё делаете правильно:

Function Foo( _
		ByVal Buffer As WString Ptr, _
		ByVal Length As Integer _
	)As Boolean
	
	' Используем буфер для промежуточных вычислений
	Calculate(Buffer, ...)

	' Что‐то делаем:
	Dim res As Boolean = Initialize(...)
	If res = False Then
		Return False
	End If

	' Работаем с буфером
	write(Bufer, Length, ...)

	Return True

End Function

Однако когда вы установите на машину клиента новую версию своей DLL, тогда перестанет работать установленная программа другого человека, который использовал вашу DLL:

var buf = CAllocate(Length)

' Вызываем функцию из DLL
Foo(buf, Length)

' Выводим результат
' Получаем мусор на выходе — программа перестала работать
PrintBuffer(buf, Length)

' Очистка
Deallocate(buf)

Вина ваша? Нет. Но что скажет пользователь? «Не ставьте новую версию «Ваш Продукт» — он ломает «Программу Другого Человека»!» или: «Проклятый DLL Hell, проклятый Microsoft и проклятый Билл Гейтс!» или просто: «Компьютеры такие глупые! Их так тяжело использовать!»

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment