Почему функция CreateProcess изменяет переданную на вход командную строку?

Одна из неприятных особенностей функции CreateProcess состоит в том, что параметр lpCommandLine должен быть указателем на изменяемые данные. Если вы передадите указатель на память, которая не может быть изменена (например, указатель на страницу, помеченную PAGE_READONLY), то все может повалиться. Комментатор Ritchie удивляется, почему этот параметр такой странный .

Вкратце, кто-то еще в 1980е хотел избежать выделения памяти . (Другая интерпретация этого: кто-то хотел быть черезчур умным.)

CreateProcess временно изменяет строку, переданную в lpCommandLine в попытке разобраться, где кончается имя программы и начинаются параметры командной строки. Функция могла бы снять копию со строки и сделать временные изменения в копии, но! если вы изменяете входную строку непосредственно, то вы экономите дорогостоящую операцию выделения памяти. В старые времена люди старались избегать выделений памяти, так что микро-оптимизации такого рода - это те вещи, о которых люди как правило беспокоились. Конечно, в наши дни, это выглядит достаточно устаревшим.

На самом деле, могут быть и серьезные технические причины (помимо чисто соображений производительности) избегать выделений памяти из кучи. Когда программа валится, отладчик "по месту" запускается функцией CreateProcess, и вы не хотите выделять память из кучи, если причиной краха программы было повреждение кучи. Иначе вы можете получить рекурсивный цикл крахов : пытаясь запустить отладчик, вы валитесь, что означает - вы пытаетесь запустить отладчик для отладки нового краха , что опять валится, и так далее. Первоначальные авторы функции CreateProcess были осторожны в плане избегания выделений памяти из кучи, так что в случае, когда функция вызывается для запуска отладчика, она не споткнется о поврежденную кучу.

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

Почему затронута только Юникод-версия? Так это потому, что ANSI версия функции просто конвертирует свои строки в Юникод и потом зовет Юникод-версию функции. Таким образом, ANSI-версия функции реализует обход ошибки как побочный эффект своей первоначальной задачи: строка, переданная в Юникод-версию функции - это временная строка!

Упражнение: Почему для ANSI-версии CreateProcess нормально выделять временную строку из кучи, а для Юникодной функции - нет?

 

оригинал статьи