Pergunta

considerar o programa abaixo

    char str[5];
    strcpy(str,"Hello12345678");
    printf("%s",str);

Ao executar este programa dá falha de segmentação.

Mas quando strcpy é substituído por seguinte, o programa funciona muito bem.

strcpy(str,"Hello1234567");

Assim questão é que deve falhar ao tentar copiar para str qualquer outra cadeia de comprimento mais de 5 caracteres.

Então, por que ele é não cair para "Hello1234567" e apenas bater para "Hello12345678", ou seja de corda com um comprimento de 13 ou mais de 13.

Este programa foi executado na máquina de 32 bits.

Foi útil?

Solução

Existem três tipos de comportamento padrões que você deve estar interessado em.

1 / comportamento definido . Isto irá funcionar em todas as implementações obedeçam. Utilize este livremente.

2 / comportamento definido pela implementação . Como foi dito, isso depende da implementação, mas pelo menos ele ainda está definido. Implementações são necessárias para documentar o que fazer nestes casos. Use isto se você não se preocupam com a portabilidade.

3 / Comportamento indefinido . Nada pode acontecer. E queremos dizer qualquer , até e incluindo todo o seu computador em colapso em uma singularidade nua e engolindo-se, você e uma grande proporção de seus colegas de trabalho. Nunca use isso. Sempre! Seriamente! Não me faça ir até aí.

copiar mais que 4 caracteres e um-zero bytes para uma char[5] é comportamento indefinido.

A sério, não importa por que seu programa trava com 14 caracteres, mas não 13, você está quase certamente substituir algumas informações não cair na pilha e seu programa provavelmente irá produzir resultados incorretos de qualquer maneira. Na verdade, o acidente é melhor, pelo menos desde que o pare contando com os possíveis efeitos ruins.

aumentar o tamanho da matriz para algo mais adequado (char[14], neste caso, com a informação disponível) ou utilizar qualquer outra estrutura de dados que pode lidar.


Atualização:

Uma vez que você parece tão preocupado com descobrir por que um extra de 7 caracteres não causa problemas, mas 8 caracteres faz, vamos encarar o layout pilha possível ao entrar main(). Eu digo "possível" desde o layout real depende da convenção de chamada que usa seu compilador. Desde que o código de arranque C chama main() com argc e argv, a pilha no início do main(), depois de alocar espaço para um char[5], poderia ser assim:

+------------------------------------+
| C start-up code return address (4) |
| argc (4)                           |
| argv (4)                           |
| x = char[5] (5)                    |
+------------------------------------+

Quando você escreve o Hello1234567\0 bytes com:

strcpy (x, "Hello1234567");

para x, ele substitui o argc e argv mas, no retorno da main(), tudo bem. Especificamente povoa Hello x, 1234 povoa argv e 567\0 povoa argc. Desde que você realmente não tentar uso argc e / ou argv depois disso, você vai ficar bem:

+------------------------------------+ Overwrites with:
| C start-up code return address (4) |
| argc (4)                           |   '567<NUL>'
| argv (4)                           |   '1234'
| x = char[5] (5)                    |   'Hello'
+------------------------------------+

No entanto, se você escrever Hello12345678\0 (note o extra "8") para x, ele substitui o argc e argv e também um byte do endereço de retorno para que, quando as tentativas main() para voltar ao o código de arranque C, ele sai em terra de fadas em vez disso:

+------------------------------------+ Overwrites with:
| C start-up code return address (4) |   '<NUL>'
| argc (4)                           |   '5678'
| argv (4)                           |   '1234'
| x = char[5] (5)                    |   'Hello'
+------------------------------------+

Novamente, isso depende inteiramente da convenção de chamada do seu compilador. É possível um compilador diferente sempre pad fora matrizes para um múltiplo de 4 bytes eo código não iria falhar lá até que você escreveu mais três caracteres. Mesmo o mesmo compilador pode alocar variáveis ??na armação da pilha de forma diferente para garantir o alinhamento é satisfeita.

Isso é o que eles querem dizer com indefinido:. Você não sei o que vai acontecer

Outras dicas

Você está copiando para a pilha, por isso é dependente do que o compilador tem colocado na pilha, para a quantidade de dados extra será necessário para travar o seu programa.

Alguns compiladores pode produzir código que irá falhar com apenas um único byte sobre o tamanho do buffer. - É indefinido o que o comportamento é

Eu acho que o tamanho 13 é suficiente para substituir o endereço de retorno, ou algo semelhante, que falha quando a função retorna. Mas um outro compilador ou outra plataforma pode / vai bater com um comprimento diferente.

Além disso o programa pode falhar com um comprimento diferente se ele correu por um longo tempo, se algo menos importante estava sendo substituído.

Para a plataforma Intel de 32 bits a explicação é a seguinte. Quando você declarar char [5] na pilha o compilador realmente aloca 8 bytes por causa do alinhamento. Então é típico para funções a ter a seguinte prólogo:

push ebp
mov ebp, esp

isso poupa valor do Registro ebp na pilha, então se move esp registar valor em ebp para usar esp valor para acessar os parâmetros. Isto leva a mais 4 bytes na pilha a ser ocupado com o valor ebp.

No ebp epílogo é restaurada, mas o seu valor é normalmente usado apenas para acessar os parâmetros de função alocada-stack, então a substituição não pode ferir na maioria dos casos.

Então você tem o seguinte layout (pilha cresce para baixo na Intel.): 8 bytes para sua matriz, em seguida, 4 bytes para ebp, em seguida, normalmente o endereço do remetente

É por isso que você precisa para substituir pelo menos 13 bytes para travar o seu programa.

Para adicionar as respostas acima: você pode testar para erros como estes com uma ferramenta como Valgrind . Se você estiver no Windows, ter um olhar para esta discussão SO .

Depende do que está na pilha após a matriz "str". Você acabou de acontecer para não ser pisar em qualquer coisa crítica até que a cópia que muitos personagens.

Por isso, vai depender do que o resto é na função, o compilador que você usa e, possivelmente, as opções do compilador também.

13 é 5 + 8, sugerindo que existem duas palavras não críticos após a matriz str, então algo crítico (talvez o endereço de retorno)

Essa é a beleza pura de comportamento indefinido (UB):. Ela é indefinida

O seu código:

char str[5];
strcpy(str,"Hello12345678");

Grava 14 bytes / caracteres para str que só pode conter 5 bytes / caracteres. Isso invoca UB.

Q:. Então, por que ele não está falhando para "Hello1234567" e apenas bater para "Hello12345678", ou seja de corda com um comprimento de 13 ou mais de 13

Como o comportamento é indefinido. Use strncpy. Veja esta página http://en.wikipedia.org/wiki/Strcpy para mais informações.

strncpy é inseguro uma vez que não adicionar uma terminação NULL se a cadeia de origem tem um comprimento> = n onde n é o tamanho da cadeia de destino.

char s[5];
strncpy(s,5,"test12345");
printf("%s",s); // crash

Nós sempre usar strlcpy para aliviar este.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top