Почему этот цикл for застревает на второй итерации в C?

На языке C я создаю программу, использующую WinAPI. Для этой программы я пишу функцию, которая будет включать указанные привилегии. Вот что у меня есть:

void EnablePrivileges(LPCWSTR awszPrivileges[], DWORD dwCount){
     HANDLE hToken;
     if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)) {
          printf("Failed to open process token. Error: %lu\n", GetLastError());
          return;
     }
     TOKEN_PRIVILEGES tp;
     tp.PrivilegeCount = dwCount;
     for (DWORD i = 0; i < dwCount; ++i) {
          wprintf(TEXT("Privilege constant: %ls | Iterator value: %i\n"), awszPrivileges[i], i);
          if (!LookupPrivilegeValueW(NULL, awszPrivileges[i], &tp.Privileges[i].Luid)) {
               printf("Failed to lookup privilege value. Error: %lu\n", GetLastError());
               CloseHandle(hToken);
               return;
          }
          tp.Privileges[i].Attributes = SE_PRIVILEGE_ENABLED;
     }
     if (!AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), NULL, NULL)) {
          printf("Failed to adjust token privileges. Error: %lu\n", GetLastError());
     } else {
          printf("Token privileges adjusted successfully.\n");
     }
     CloseHandle(hToken);
}

int main() {
     LPCWSTR awszPrivileges[] = {SE_TAKE_OWNERSHIP_NAME, SE_AUDIT_NAME, SE_RESTORE_NAME};
     EnablePrivileges(awszPrivileges, 3);
     system("pause");
     return 0;
}

Он компилируется без ошибок.

Однако, когда я затем запускаю его с правами администратора, он выдает следующее:

Privilege constant: SeTakeOwnershipPrivilege | Iterator value: 0
Privilege constant: SeAuditPrivilege | Iterator value: 1
Privilege constant: SeAuditPrivilege | Iterator value: 1
Privilege constant: SeAuditPrivilege | Iterator value: 1
Privilege constant: SeAuditPrivilege | Iterator value: 1
Privilege constant: SeAuditPrivilege | Iterator value: 1

... и так далее.

Это также произошло, когда пытались включить только две привилегии. Однако успешно работает только с одним.

Что заставляет цикл for вести себя подобным образом? Как исправить эту ошибку?

Пожалуйста, не отмечайте спам. C, C# и C++ — это не один и тот же язык, поскольку они начинаются с буквы C, так же как автомобиль, кошка и морковка не связаны друг с другом. Пожалуйста, используйте только тот тег, который действительно соответствует языку, который вы используете. Если вы не уверены, используете ли вы C или C++, прекратите писать код, пока не разберетесь в нем, потому что вы ничего не добьетесь.

Ken White 05.04.2024 02:06

@Chris Это C, но я уверен, что с C++ возникнут некоторые проблемы.

Hantalyte 05.04.2024 02:08

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

Ken White 05.04.2024 02:09

@KenWhite Я пишу на C, я ясно дал это понять. Причина, по которой я также отметил «C++», заключается в том, что я уверен, что ошибка сохранится и в этом языке. Я также попробовал скомпилировать компилятором C++, но ошибка осталась.

Hantalyte 05.04.2024 02:10

Вы объявили переменную стека TOKEN_PRIVILEGES tp; — вы не можете получить доступ к элементам в массиве «любого размера», как вы сейчас делаете с tp.Privileges[i], потому что это адресация к концу структуры данных. Эта структура предназначена для выделения размера, который отражает фактический объем памяти, необходимый для массива, чтобы вы могли обращаться к концу поля Privileges. См. Learn.microsoft.com/en-us/windows/win32/api/winnt/…

paddy 05.04.2024 02:11

Ваше оправдание неправильного использования тега не имеет значения. Теги здесь имеют значение и актуальность, и вам следует использовать только те теги, которые действительно применимы к содержанию вашего сообщения. Если ваш код написан на C, то добавление тега C++ является неправильным использованием системы тегов. Не отмечайте спам.

Ken White 05.04.2024 02:13
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
6
76
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы обращаетесь к концу tp.Privileges. Размер этого массива равен 1. Как указано в документации :

Важно. Константа ANYSIZE_ARRAY определена как 1 в общедоступном заголовке Winnt.h. Чтобы создать этот массив с более чем одним элементом, необходимо выделить достаточно памяти для того, чтобы структура учитывала дополнительные элементы.

Вы должны выделить (правильно выровненный) блок памяти размером не менее sizeof(TOKEN_PRIVILEGES) + (dwCount - 1) * sizeof(LUID_AND_ATTRIBUTES) и инициализировать там свой TOKEN_PRIVILEGES объект.

Более традиционный способ определить размер — заставить компилятор выполнить математические действия, т. е. offsetof(TOKEN_PRIVILEGES, Privileges[dwCount]) (используйте FIELD_OFFSET() , если ваш компилятор не поддерживает offsetof() ). Обоснование конечного массива размера 1: Почему некоторые структуры заканчиваются массивом размера 1?,

IInspectable 05.04.2024 09:32

Другие вопросы по теме