Armadilloフォーラム

popenの使い方

sakashita_spc

2019年7月4日 14時17分

お世話になります。

840/Atmark-distを使っています。
popenを使っているのですが、以下のようなコーディングは問題ないでしょうか?

int count;
FILE *f1,*f2;
f1=popen("XXXXX","r")

for(count=0;count<10;count++)
{
f2=popen("YYYYY","r");
....
pclose(f2);
}
pclose(f1);

最初にpopenしたのち、pcloseする前に、popenをするケース。
上記の関数は単純化したものですが、f1,f2は同一プロセス、スレッドでの実行です。

以上、アドバイスよろしくお願いします。


コメント

sakashita_spc

2019年7月5日 0時42分

サンプルコードをつくてやってみましたが、

*** glibc detected *** ./demo1: double free or corruption (out): 0x00012260 ***
Aborted

のエラーが出てしまいました。(外側のループのpclose()でのエラーですね。)
今回、同一プロセス、同一スレッドでやったのですが、異なるスレッドで
動作すればいいのですが、方法があればお願いします。

以上、よろしくお願いします。

y.nakamura

2019年7月5日 3時00分

中村です。

> *** glibc detected *** ./demo1: double free or corruption (out): 0x00012260 ***
> Aborted
>
> のエラーが出てしまいました。(外側のループのpclose()でのエラーですね。)

問題なく動くと思いますけど・・・

テストソース

#include
#include

int main(int argc, char *argv[])
{
int count;
FILE *f1, *f2;
char buf[1024];

f1 = popen("/bin/ps", "r");
if (f1 == NULL) {
perror("popen f1");
return 1;
}

printf("-----------------------\n");
while (fgets(buf, sizeof buf, f1) != NULL) {
printf("%s", buf);
}
printf("-----------------------\n");

for (count = 0; count < 5; count++) {
printf("==== count=%d =====\n", count);

f2 = popen("/bin/ls -la", "r");
if (f2 == NULL) {
perror("popen f2");
return 1;
}

while (fgets(buf, sizeof buf, f2) != NULL) {
printf("%s", buf);
}

if (pclose(f2) < 0) {
perror("pclose f2");
return 1;
}

printf("==================\n");
}

if (pclose(f1) < 0) {
perror("pclose f1");
return 1;
}

return 0;
}

(ループ10回でも試してますが、投稿にあたり、
結果が長くなるので5回にしました)

結果

-----------------------
PID TTY TIME CMD
16915 pts/0 00:00:00 bash
17625 pts/0 00:00:00 a.out
17626 pts/0 00:00:00 sh
17627 pts/0 00:00:00 ps
-----------------------
==== count=0 =====
合計 20
drwxr-xr-x 2 atmark atmark 4096 7月 5 02:52 .
drwxr-xr-x 7 atmark atmark 4096 7月 5 02:34 ..
-rwxr-xr-x 1 atmark atmark 5888 7月 5 02:52 a.out
-rw-r--r-- 1 atmark atmark 830 7月 5 02:51 test.c
==================
==== count=1 =====
合計 20
drwxr-xr-x 2 atmark atmark 4096 7月 5 02:52 .
drwxr-xr-x 7 atmark atmark 4096 7月 5 02:34 ..
-rwxr-xr-x 1 atmark atmark 5888 7月 5 02:52 a.out
-rw-r--r-- 1 atmark atmark 830 7月 5 02:51 test.c
==================
==== count=2 =====
合計 20
drwxr-xr-x 2 atmark atmark 4096 7月 5 02:52 .
drwxr-xr-x 7 atmark atmark 4096 7月 5 02:34 ..
-rwxr-xr-x 1 atmark atmark 5888 7月 5 02:52 a.out
-rw-r--r-- 1 atmark atmark 830 7月 5 02:51 test.c
==================
==== count=3 =====
合計 20
drwxr-xr-x 2 atmark atmark 4096 7月 5 02:52 .
drwxr-xr-x 7 atmark atmark 4096 7月 5 02:34 ..
-rwxr-xr-x 1 atmark atmark 5888 7月 5 02:52 a.out
-rw-r--r-- 1 atmark atmark 830 7月 5 02:51 test.c
==================
==== count=4 =====
合計 20
drwxr-xr-x 2 atmark atmark 4096 7月 5 02:52 .
drwxr-xr-x 7 atmark atmark 4096 7月 5 02:34 ..
-rwxr-xr-x 1 atmark atmark 5888 7月 5 02:52 a.out
-rw-r--r-- 1 atmark atmark 830 7月 5 02:51 test.c
==================

// Armadilloではなくて、ATDE6で動かしてます

--
なかむら

sakashita_spc

2019年7月11日 23時12分

中村様
お世話になります。

連絡ありがとうございます。
popenのソースを検索すると。

A)https://android.googlesource.com/platform/bionic/+/3884bfe9661955543ce2…
B)https://www.retro11.de/ouxr/211bsd/usr/src/lib/libc/gen/popen.c.html

の2種類があるようで、(A)ソースを利用して、Armadilloで動作させたところ、動作しました。
おそらく、atmark-distのソースは(B)を利用していると、推測します。

(A)はOpenしたfpがリスト構造のバッファに保存されるのですが、(B)ではグローバル変数に保存され、2回目のpopenで1回目が
上書きされてしまっていると思います。

ありがとうございました。

y.nakamura

2019年7月12日 1時55分

中村です。

Armadillo-840で実行してみました。
問題ないようです。

> popenのソースを検索すると。
> A)https://android.googlesource.com/platform/bionic/+/3884bfe9661955543ce2…
> B)https://www.retro11.de/ouxr/211bsd/usr/src/lib/libc/gen/popen.c.html
> の2種類があるようで、(A)ソースを利用して、Armadilloで動作させたところ、動作しました。
> おそらく、atmark-distのソースは(B)を利用していると、推測します。

少し長くなりますが、popenのソースについて書いておきます。

atmark-distが使うlibcは、ATDEに入っている
クロスコンパイル済みのglibcです。

これを説明しているところはたくさんありますが、
たとえば・・・
https://users.atmark-techno.com/forum/armadillo/962
| 開発環境(ATDE)にインストールされているビルド済みのライブラリが
| 組み込まれるようになっています。
| (ビルド時にglibcをビルドする必要もありません)
です。

今回のテスト環境は、ちょっと古いのを使っていますが、
- atde5-i386-20161130
- atmark-dist-20170726
- linux-3.4-at23
です。

この環境でビルドしたカーネルとユーザランドを
Armadillo-840に書き込んで、
テストプログラムをarm-linux-gnueabihf-gccしたものを
Armadillo-840に転送して実行しました。

この私の環境で使用されているglibcは、
atmark-distのビルドディレクトリの中をみると、

atmark@atde5:~/work$ cd atmark-dist-20170726/
atmark@atde5:~/work/atmark-dist-20170726$ ls -l romfs/lib/libc*
-rwxr-xr-x 1 atmark atmark 905332 9月 26 2017 romfs/lib/libc-2.13.so
lrwxrwxrwx 1 atmark atmark 17 9月 26 2017 romfs/lib/libc.so.6 -> /lib/libc-2.13.so
lrwxrwxrwx 1 atmark atmark 19 9月 26 2017 romfs/lib/libcap.so.2 -> /lib/libcap.so.2.22
-rw-r--r-- 1 atmark atmark 11028 9月 26 2017 romfs/lib/libcap.so.2.22
lrwxrwxrwx 1 atmark atmark 22 9月 26 2017 romfs/lib/libcom_err.so.2 -> /lib/libcom_err.so.2.1
-rw-r--r-- 1 atmark atmark 9796 9月 26 2017 romfs/lib/libcom_err.so.2.1
-rw-r--r-- 1 atmark atmark 26184 9月 26 2017 romfs/lib/libcrypt-2.13.so
lrwxrwxrwx 1 atmark atmark 21 9月 26 2017 romfs/lib/libcrypt.so.1 -> /lib/libcrypt-2.13.so
-rw-r--r-- 1 atmark atmark 1127780 9月 26 2017 romfs/lib/libcrypto.so.1.0.0

となっていますので、glibc-2.13が使われていることがわかります。

Armadillo-840にもこれと同じものがインストールされています。

[root@armadillo840-0 (ttySC2) ~]# ls -l /lib/libc*
-rwxr-xr-x 2 root root 905332 Sep 26 2017 /lib/libc-2.13.so*
lrwxrwxrwx 1 root root 17 Sep 26 2017 /lib/libc.so.6 -> /lib/libc-2.13.so*
lrwxrwxrwx 1 root root 19 Sep 26 2017 /lib/libcap.so.2 -> /lib/libcap.so.2.22
-rw-r--r-- 1 root root 11028 Sep 26 2017 /lib/libcap.so.2.22
lrwxrwxrwx 1 root root 22 Sep 26 2017 /lib/libcom_err.so.2 -> /lib/libcom_err.so.2.1
-rw-r--r-- 1 root root 9796 Sep 26 2017 /lib/libcom_err.so.2.1
-rw-r--r-- 1 root root 26184 Sep 26 2017 /lib/libcrypt-2.13.so
lrwxrwxrwx 1 root root 21 Sep 26 2017 /lib/libcrypt.so.1 -> /lib/libcrypt-2.13.so
-rw-r--r-- 1 root root 1127780 Sep 26 2017 /lib/libcrypto.so.1.0.0

glibc-2.13のソースは、たぶん、
http://ftp.gnu.org/gnu/glibc/
にある glibc-2.13.tar.gz だと思います。

ダウンロードして中をみてみたところ、
たぶん、popenのソースは
glibc-2.13/libio/iopopen.c
だと思います。

先日のテストプログラムは、次のように修正して、
popenしたFILEのfilenoを表示するようにしてみました。


#include
#include

int main(int argc, char *argv[])
{
int count;
FILE *f1, *f2;
char buf[1024];

f1 = popen("/bin/ps", "r");
if (f1 == NULL) {
perror("popen f1");
return 1;
}
printf("fileno(f1)=%d\n", fileno(f1));

printf("-----------------------\n");
while (fgets(buf, sizeof buf, f1) != NULL) {
printf("%s", buf);
}
printf("-----------------------\n");

for (count = 0; count < 5; count++) {
printf("==== count=%d =====\n", count);

f2 = popen("/bin/ls -la", "r");
if (f2 == NULL) {
perror("popen f2");
return 1;
}
printf("fileno(f2)=%d\n", fileno(f2));

while (fgets(buf, sizeof buf, f2) != NULL) {
printf("%s", buf);
}

if (pclose(f2) < 0) {
perror("pclose f2");
return 1;
}
printf("pclose(f2) OK\n");

printf("==================\n");
}

if (pclose(f1) < 0) {
perror("pclose f1");
return 1;
}
printf("pclose(f1) OK\n");

return 0;
}

--
なかむら

y.nakamura

2019年7月12日 2時04分

中村です。

書き忘れがありました。

> atmark-distのビルドディレクトリの中をみると、
> atmark@atde5:~/work$ cd atmark-dist-20170726/
> atmark@atde5:~/work/atmark-dist-20170726$ ls -l romfs/lib/libc*
> -rwxr-xr-x 1 atmark atmark 905332 9月 26 2017 romfs/lib/libc-2.13.so
...
>
> となっていますので、glibc-2.13が使われていることがわかります。

この元になっている(atmark-distのビルドでコピーされる元の)
libc-2.13.soは、ATDEに入っている次のものです。

atmark@atde5:~$ locate libc-2.13.so
/home/atmark/work/atmark-dist-20170726/romfs/lib/libc-2.13.so
/lib/i386-linux-gnu/libc-2.13.so
/lib/i386-linux-gnu/i686/cmov/libc-2.13.so
/usr/arm-linux-gnueabi/lib/libc-2.13.so
/usr/arm-linux-gnueabihf/lib/libc-2.13.so
/usr/lib/debug/lib/i386-linux-gnu/libc-2.13.so
/usr/lib/debug/lib/i386-linux-gnu/i686/cmov/libc-2.13.so
/usr/lib/debug/lib/i386-linux-gnu/i686/nosegneg/libc-2.13.so

atmark@atde5:~$ ls -l /usr/arm-linux-gnueabihf/lib/libc-2.13.so
-rwxr-xr-x 1 root root 905332 2月 12 2016 /usr/arm-linux-gnueabihf/lib/libc-2.13.so

atmark@atde5:~$ cmp /usr/arm-linux-gnueabihf/lib/libc-2.13.so \
> work/atmark-dist-20170726/romfs/lib/libc-2.13.so
(何も表示されないので2つは同じファイル)

--
なかむら

sakashita_spc

2019年7月20日 1時11分

中村様
お世話になります。

いろいろありがとうございました。
もう一度、確認してみます。

いったんクローズでお願いします。