試験運用中なLinux備忘録・旧記事

はてなダイアリーで公開していた2007年5月-2015年3月の記事を保存しています。

Mandriva Linux 2009.1でGNU screenのRPMパッケージが再ビルドできない件とその対処(後半)

Mandriva Linux 2009.1でGNU screenのRPMパッケージが再ビルドできない件とその対処(前半)」の続き。

    1. C言語のprintf()関数のフォーマット引数に関する実験
    2. ソースへの修正

C言語のprintf()関数のフォーマット引数に関する実験
まずはソースを用意。
ファイル名: nofmtargtest.c

#include <stdio.h>
#include <stdlib.h>
/*
 * gcc -Wall -Wformat -Werror=format-security nofmtargtest.c -o nofmtargtest && echo OK || echo NG
 * gcc -Wall nofmtargtest.c -o nofmtargtest
 */
int
main (int argc, char *argv[])
{
  char str[] = "Hello, Work!!\n";
  printf ("FooBar\n");  /* OK */
  printf (str);         /* NG */
  return EXIT_SUCCESS;
}

これをコンパイルしようとすると

gcc -Wall -Wformat -Werror=format-security nofmtargtest.c -o nofmtargtest && echo OK || echo NG
nofmtargtest.c: In function ‘main’:
nofmtargtest.c:12: error: フォーマットは非文字列リテラルで、且つフォーマット引数を持ちません
NG

となる。1つ目のprintf()は直接ダブルクォートされた文字列(リテラル)を指定しているので問題はないが、次の行がダメになっている。
そこで試しに後ろにNULLを付けてみることにした。
ファイル名: nullfmtargtest.c

#include <stdio.h>
#include <stdlib.h>
/*
 * gcc -Wall -Wformat -Werror=format-security nullfmtargtest.c -o nullfmtargtest && echo OK || echo NG
 */
int
main (int argc, char *argv[])
{
  char str[] = "Hello, Work!!\n";
  printf ("FooBar\n");  /* OK */
  printf (str, NULL);   /* OK */
  return EXIT_SUCCESS;
}

今度はビルドができた。

gcc -Wall -Wformat -Werror=format-security nullfmtargtest.c -o nullfmtargtest && echo OK || echo NG
OK
$ ./nullfmtargtest 
FooBar
Hello, Work!!

ソースへの修正
GNU screenのソースに対しては、screen.c中の「, strnomem);」という文字列を「, strnomem, NULL);」に全置換することで解決した。同様に幾つかのソースファイルでも置換が必要となった(要領は全て同じ)。
対象の.specファイルではconfigureスクリプトの実行後にPerlを用いて幾つかの置換処理を行っていたため、それにならって

perl -pi -e 's|, strnomem\);|, strnomem, NULL\);|' screen.c fileio.c misc.c resize.c socket.c window.c termcap.c process.c
perl -pi -e 's|, \*cmdv\);|, \*cmdv, NULL\);|' fileio.c display.c
perl -pi -e 's|, str\);|, str, NULL\);|' ansi.c
perl -pi -e 's|LockEnd\);|LockEnd, NULL\);|' attacher.c

を後ろに付け加えた。
作成したパッケージは別館の配布ページに公開している。
(2014/10/12)配布ページは削除済み。

使用したバージョン: