Статические глобальные переменные и глобальные переменные C

У меня есть программа ниже. Если я объявлю переменные a, b, c статическими глобальными переменными, это приведет к ошибке сегментации, но если я объявлю их нестатическими глобальными или локальными переменными, это не приведет к ошибке сегментации. Почему так себя ведет? Я знаю, что данных больше, чем могут хранить переменные, но почему он выдает ошибку seg, когда объявлен только статический? Хранятся ли статически объявленные переменные в какой-то другой части кадра стека, где перезапись не разрешена?

РЕДАКТИРОВАТЬ: я знаю, что strcpy небезопасен. Но это не моя проблема. Я хочу понять, почему одно переполнение дает segfault, а другое переполнение может не давать segfault.

#include<stdio.h>
#include<string.h>

static char a[16];
static char b[16];
static char c[32];

int main(int argc, char *argv[]){

// char a[16];
 //char b[16];
 //char c[32];
    strcpy(a,"0123456789abcdef");
    strcpy(b,"0123456789abcdef");
    strcpy(c,a);
    strcpy(c,b);
    printf("a = %s\n",a);
    return 0;
}

person Neo    schedule 07.04.2015    source источник
comment
Когда вы пишете за пределы буфера, вы записываете в произвольную память, поведение которой может быть неопределенным.   -  person merlin2011    schedule 08.04.2015
comment
Это то, что называется неопределенным поведением. Не спрашивайте о том, что не определено.   -  person Eugene Sh.    schedule 08.04.2015
comment
Странно, что вы получаете сбой только в том случае, если они статические, поскольку разница между статическими и нестатическими глобальными переменными должна быть только вопросом области действия. (Конечно, это разрешено поведение в соответствии с языком C, который говорит, что все может случиться)   -  person user253751    schedule 08.04.2015
comment
Я подозреваю, что ваш компилятор выделяет статические глобальные переменные иначе, чем нестатические глобальные переменные, поэтому вскоре после окончания c оказывается 0 байт, но его нет, когда они не являются статическими.   -  person user253751    schedule 08.04.2015
comment
доступ к памяти за пределами конца буфера является неопределенным поведением. Поскольку это поведение undefined, может случиться что угодно. что-либо. поэтому иногда поведение является событием ошибки сегмента. иногда это что-то скрытое, что портит другие данные, такие как цепочка вызовов стека. иногда это что-то доброкачественное. Никогда не ждите определенного поведения. Такого неопределенного поведения следует всегда избегать. Стоимость может быть огромной, когда некоторые данные повреждены, и пользователь будет очень недоволен, если приложение завершится с ошибкой сегмента.   -  person user3629249    schedule 08.04.2015


Ответы (2)


выравнивание памяти имеет значение в переменной стека. Попробуйте с -fstack-protector-strong или аналогичной опцией защиты стека, и вы увидите сбой. Также объявите int после c и переполните ваш массив c, вы можете увидеть сбой. вам нужно убедиться, что нет отступов. поскольку b - это массив, все, что вы переполняете из "a", переходит в b. Попробуйте что-то вроде:

struct foo {
        char c[10];
        int x;
    } __attribute__((packed));

вы увидите сбой при переполнении c.

Вы сталкиваетесь с неопределенным поведением при переполнении.

person resultsway    schedule 07.04.2015
comment
Здесь нет переменных стека. - person nobody; 08.04.2015
comment
просто создайте одну структуру foo f; - person resultsway; 22.04.2015

Обратите внимание, что строка const char* в C всегда заканчивается 0, а это означает, что строка «0123456789abcdef» на самом деле состоит из 17 символов: "0123456789abcdef\0"

Я предлагаю вам всегда использовать безопасную версию

strncpy() 

Вы также можете взглянуть на документацию, в которой явно указано, что нулевой символ включен.

http://www.cplusplus.com/reference/cstring/strcpy/

person slux83    schedule 07.04.2015
comment
strncpy не является безопасным, и в данном случае это не поможет. Существует очень мало ситуаций, когда strncpy является правильной функцией. - person M.M; 08.04.2015
comment
@ slux83 спасибо за это. Я знаю это, но мой вопрос в том, почему он не дает segfault, когда он не статичен. - person Neo; 08.04.2015
comment
Это не дает вам неопределенного поведения. Это также может привести к ошибке, если ваша программа не будет такой короткой. Проблема повреждения стека заключается в том, что время обнаружения сбоя непредсказуемо. - person slux83; 08.04.2015
comment
@Matt с использованием strncpy всегда является хорошей практикой, потому что вы ограничиваете копию, указывая размер вашего буфера, на случай, если вы пропустите нулевой символ по какой-то неясной причине. - person slux83; 08.04.2015
comment
@ slux83 нет, это плохая практика. Использование strncpy в этом случае все равно вызовет переполнение буфера (хотя и другого рода), потому что strncpy не завершает строку нулем, когда она не подходит. - person M.M; 08.04.2015