popenの使い方

お世話になります。

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は同一プロセス、スレッドでの実行です。

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

製品: 
Armadillo-840

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

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

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

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

中村です。

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

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

テストソース

#include <stdio.h>
#include <errno.h>
 
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で動かしてます

--
なかむら

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

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

A)https://android.googlesource.com/platform/bionic/+/3884bfe9661955543ce203c60f9225bbdf33f6bb/libc/unistd/popen.c
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回目が
上書きされてしまっていると思います。

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

中村です。

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

> popenのソースを検索すると。
> A)https://android.googlesource.com/platform/bionic/+/3884bfe9661955543ce203c60f9225bbdf33f6bb/libc/unistd/popen.c
> 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 <stdio.h>
#include <errno.h>
 
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;
}

--
なかむら

中村です。

書き忘れがありました。

> 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つは同じファイル)

--
なかむら