warning: ‘builtin_memcpy’ accessing 9 bytes at offsets 1 and 0 overlaps 8 bytes at offset 1
警告:転送領域が重なったのでrestrict修飾違反で未定義動作
[-Wrestrict]
■1.配列をずらす時の失敗例(memcpy)
void f1(void)
{
char buf[]="0123456789";
memcpy(&buf[1],&buf[0],9);
printf("%s\n",buf);
}
memcpy( )の転送領域が重なっているので
restrict 修飾違反となり未定義動作となります。
注意:
・最適化(ーOオプション使用)しないとこの警告は出ません。
・実験ではgccとclangの結果は異なりました。
・最適化レベルを変えると結果も変わりました。
■2.配列をずらす時の修正例(memmove)
void f2(void)
{
char buf[]="0123456789";
memmove(&buf[1],&buf[0],9);
printf("%s\n",buf);
}
memcpy( )の代わりに
memmove( )を使用すると安全に動作します。
■3.sprintfの失敗例(入出力が同じ)
warning: ‘sprintf’ argument 4 overlaps destination object ‘output’
警告:sprintfの入力引数が出力引数と同じ
[-Wrestrict]
#include <stdio.h>
int main(void)
{
char output[1024] = "filename";
char input[] = "dirname" ;
sprintf(output,"%s/%s",input,output);
printf("%s\n",output);
}
出力バッファの第1引数outputと
入力バッファの第4引数outputが同じなので
未定義動作のバグとなります。
”dirname/filename”の出力を期待しても、
未定義動作なので何が表示されるかわかりません。
修正例を以下に示します。
■4.sprintfの修正例(入出力を分ける)
#include <stdio.h>
int main(void) {
char output[1024];
char *fn = "filename";
char *dn = "dirname" ;
sprintf(output,"%s/%s",dn,fn);
printf("%s\n",output);
}
参考:
軽率にも次のようなコードを使っているプログラムがある。
https://linuxjm.osdn.jp/html/LDP_man-pages/man3/printf.3.html
コピー元の領域と コピー先の領域が重なってはならない。
https://linuxjm.osdn.jp/html/LDP_man-pages/man3/memcpy.3.html
C-FAQ 11.25: memcpy()とmemmove()の違いは。
http://www.kouno.jp/home/c_faq/c11.html#25