-2

私はCで簡単なプログラムを書いています:

int main(int argc, char** argv) {
    unsigned char* line = (unsigned char* ) malloc(0xFFFF);
    while (gets(line) > 0) {
        if (line[0] == 'l') {
            if (line[2]=='.' && line[3] == '.') {
                printf("forbidden path");
            } 
            unsigned char* res = (unsigned char* ) malloc(0xFFFF);
            unsigned char* cmd = (unsigned char* ) malloc(strlen(line) +
            1 + strlen(" | grep -v xml") + strlen("/home/files/"));
            strcpy(cmd, "ls ");
            strcpy(cmd + 3, "/home/boris/0servfiles/");
            strcpy(cmd + 3 + strlen("/home/files/"), line + 2);
            strcpy(cmd + 3 + strlen("/home/files/") + strlen(line + 2), " | grep -v xml");
            execwthr(cmd, res);
            printf("%s\n%s", cmd, res);
            free(cmd);
            free(res);
        } else if (line[0] == 'm') {
            if (line[2]=='.' && line[3] == '.') {
                printf("forbidden path");
            } 
            unsigned char res = (unsigned char* ) malloc(0xFFFF);
            unsigned char* cmd = (unsigned char* ) malloc(strlen(line) +
                1 + strlen("/home/files/"));
            strcpy(cmd, "mkdir ");
            strcpy(cmd + 6, "/home/files/");
            strcpy(cmd + 6 + strlen("/home/files/"), line + 2);
            execwthr(cmd, res);
            printf("%s\n%s", cmd, res);
            free(cmd);
            free(res);
        }
    }
    return (EXIT_SUCCESS);
}

小さな問題が 1 つあります。「h」という名前のフォルダーを作成しようとすると、次のようになります。

m l
mkdir /home/files)l

どうしたの?前もって感謝します!

4

4 に答える 4

2

あなたは機能を認識していないようですstrcat()。これを使用すると、コードが大幅に簡素化されます。

また、単純なシェル (または Perl) スクリプトではるかに簡単に実行できる仕事をするために C コードを書いているのはなぜですか? たとえば、スクリプトは Perl では次のようになると思います。

#!/usr/bin/perl
use strict;
while (my $line = <STDIN>) {
    chomp $line;
    my $cmd;
    if (my ($arg) = $line =~ m{^l (.*)$}) {
        $cmd = "ls /home/files/$arg | grep -v xml";
    } elsif (my ($arg) = $line =~ m{^m (.*)$}) {
        $cmd = "mkdir /home/files/$arg";
    }
    my $res = `$cmd`;
    print "$cmd\n$res\n";
}

このコードはテストされておらず、(まだ) 安全ではないことに注意してください。ただし、コードよりもはるかに短く、読みやすくなっています。これは、C がこのタスクには不適切な言語であることを示しています。:)

于 2012-04-23T21:24:07.380 に答える
2

ここには多くの問題があります。いくつかリストしますが、それらを解決すると、おそらく他のものも明らかになるでしょう。

予期しないパスが入力として提示されると、「禁止されたパス」を出力します。ただし、その無効なパスを使用して関数を続行します。これが発生した場合、おそらくプログラムから完全にエラーを出したいでしょう。

malloc()関数が失敗する可能性があります。その場合、NULL ポインタを返します。によって返される値をチェックすることはありませんmalloc。つまり、文字列操作コードが無効なポインターを使用している可能性があります。

のような関数はstrcpy()、バッファ オーバーフローに対する保護を提供しないため、使用しないでください。代わりに「安全な」バージョンを使用してください ( などstrncpy)。

この関数gets()は非常に安全ではなく、推奨されていません。代わりに、他の標準ライブラリ I/O 関数を使用してください。

このコード:

strcpy(cmd, "ls ");
strcpy(cmd + 3, "/home/boris/0servfiles/");
strcpy(cmd + 3 + strlen("/home/files/"), line + 2);

おそらくあなたがやりたいことをしていません。2 行目は長い文字列をバッファーに追加しますが、3 行目ははるかに短い文字列を収容するのに十分なだけ前方にスキップします。つまり、strcpyここでの 3 番目は、2 番目によって書き込まれた文字列を部分的に上書きしますstrcpy

次のようなコード:

strcpy(cmd, "mkdir ");
strcpy(cmd + 6, "/home/files/");
strcpy(cmd + 6 + strlen("/home/files/"), line + 2);

エラーが発生しやすく、魔法の数字でいっぱいです。あなたがしていることを正しく解釈しているのであれば、これを 1 つの呼び出しにまとめて、より意味のあるものにすることができます: sprintf(cmd, "mkdir /home/files/%s", line + 2);.

strncat()他の人が言及したように、標準機能を再実装しているようです。代わりに標準バージョンを使用することをお勧めします。このようなハードコードされた文字列を扱っている場合は、snprintf().

次の行は間違っています。

unsigned char res = (unsigned char* ) malloc(0xFFFF);

へのポインターを割り当てていますがchar、これはほぼ確実に望んでいるものではありません。

のメモリを動的に割り当てますがline、解放することはありません。

于 2012-04-23T21:50:35.380 に答える
1

このコードはかなり悪いです。strcat()関数を参照してください。

他にも多くの問題が見られます。たとえば、「禁止されたパス」が入力されたとコードが判断した場合、とにかくタスクを実行し続けます。

デバッガーを使用してこのコードをステップ実行し、実際に何が行われるかを確認する方法を学ぶことは有益です。これにより、元の質問にも回答できるようになります。

于 2012-04-23T21:24:39.267 に答える
0

snprintf基本的に、すべての醜いコードは、正しい引数を使用した1回の呼び出しで置き換えることができます。わざわざ学習しないでくださいstrcat; 他の人が言っているように、それはあなたがしていることよりも簡単ですが、それはまた脆弱なコードを書くことを容易にします。文字列を生成するすべてのニーズに使用するだけsnprintfで、コードはクリーンでシンプルになり、バグがなくなる可能性も十分にあります。

于 2012-04-23T23:33:06.593 に答える