Я переживаю всплеск интереса к системе с изменяемым изменением типа C99. Этот вопрос был вдохновлен this one.Совместимость с измененными типами и его последствия для безопасности
Проверяя код из этого вопроса, я обнаружил что-то интересное. Рассмотрим этот код:
int myFunc(int, int, int, int[][100]);
int myFunc(int a, int b, int c, int d[][200]) {
/* Some code here... */
}
Это, очевидно, не будет (и не будет) скомпилировать. Однако этот код:
int myFunc(int, int, int, int[][100]);
int myFunc(int a, int b, int c, int d[][c]) {
/* Some code here... */
}
компилируется без предупреждения (на gcc).
Это, по-видимому, означает, что модифицированный тип массива совместим с любым типом массива без изменений.
Но это еще не все. Вы ожидаете, что переменный тип изменен, по крайней мере, с тем, какая переменная используется для установки его размера. Но, похоже, это не так!
int myFunc(int, int b, int, int[][b]);
int myFunc(int a, int b, int c, int d[][c]) {
return 0;
}
Также компилируется без ошибок.
Итак, мой вопрос: это правильное стандартизованное поведение?
Кроме того, если переменный тип массива будет действительно совместим с любым массивом с одинаковыми размерами, не означает ли это, что это означает неприятные проблемы безопасности? Например, рассмотрите следующий код:
int myFunc(int a, int b, int c, int d[][c]) {
printf("%d\n", sizeof(*d)/sizeof((*d)[0]));
return 0;
}
int main(){
int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
myFunc(0, 0, 100, &arr);
return 0;
}
Компиляция и выходы 100, никаких ошибок или предупреждений, ничего. Как я вижу, это означает, что простой массив за пределами границ записывается, даже если вы строго проверяете размер своего массива с помощью sizeof
, , не делая ни одного акта и даже включив все предупреждения! Или я чего-то не хватает?
Если вы еще этого не сделали, попробуйте добавить -std = c99 -pedantic-errors в вашу строку компиляции gcc и посмотреть, не имеет значения. – jschultz410
@ jschultz410: хорошая идея, но no-it не имеет никакого значения вообще = ( – Mints97
Существует много случаев, когда компилятору было бы невозможно статически вывести значение c (например, - c вводится из stdin). Поэтому, часто бывает невозможно сделать какую-либо значимую статическую проверку типа таких параметров определения функции. Кажется, что если вы это сделаете, тогда компилятор говорит «ОК, я позволю вам передать все, что вам нужно, как d, поэтому длинный, так как его тип представляет собой двукратно индексированный массив ints. Удачи! » – jschultz410