1

lseek の後に read を呼び出すと、読み取ったバイト数が 0 になる理由がわかりません。

//A function to find the next note for a given userID;
//returns -1 if at the end of file is reached;
//otherwise, it returns the length of the found note.
int find_user_note(int fd, int user_uid) {
    int note_uid = -1;
    unsigned char byte;
    int length;

    while(note_uid != user_uid) { // Loop until a note for user_uid is found.
        if(read(fd, &note_uid, 4) != 4) // Read the uid data.
            return -1; // If 4 bytes aren't read, return end of file code.
        if(read(fd, &byte, 1) != 1) // Read the newline separator.
            return -1;

        byte = length = 0;
        while(byte != '\n') { // Figure out how many bytes to the end of line.
            if(read(fd, &byte, 1) != 1) // Read a single byte.
                return -1; // If byte isn't read, return end of file code.

            //printf("%x ", byte);
            length++;
        }
    }
    long cur_position = lseek(fd, length * -1, SEEK_CUR ); // Rewind file reading by length bytes.

    printf("cur_position: %i\n", cur_position);

    // this is debug
    byte = 0;
    int num_byte = read(fd, &byte, 1);

    printf("[DEBUG] found a %d byte note for user id %d\n", length, note_uid);
    return length;
}

外側の while ループが存在し、上記のコードが cur_position 5 を生成する場合、変数長の値は 34 です (したがって、lseek 関数が戻った後に少なくとも 34 バイトが確実に存在します)。まだ読み取るバイトがあります。

num_byte が常に 0 を返す理由を知っている人はいますか? それが私のコードの間違いである場合、それが何であるかわかりません。

参考までに、上記のコードは次のマシンで実行されました

$ uname -srvpio
Linux 3.2.0-24-generic #39-Ubuntu SMP Mon May 21 16:52:17 UTC 2012 x86_64 x86_64 GNU/Linux

アップデート:

  • ここに完全なコードをアップロードします
  • これは私が読もうとしているファイルの内容です
$ sudo hexdump -C /var/notes
00000000  e8 03 00 00 0a 74 68 69  73 20 69 73 20 61 20 74  |.....this is a t|
00000010  65 73 74 20 6f 66 20 6d  75 6c 74 69 75 73 65 72  |est of multiuser|
00000020  20 6e 6f 74 65 73 0a                              | notes.|
00000027

$
4

3 に答える 3

6

が(たとえば、32ビットマシンの)lengthよりも小さい符号なしタイプである場合、それは巨大な値になります(おそらく約4GB)。これが問題になる可能性があります。の結果を(32ビットの場合も)に格納すると、実装定義の変換(おそらく切り捨て)が適用され、再び小さな値が残ります。off_tsize_tlength*-1lseeklong

お使いのマシンは64ビットですが、おそらく32ビットのユーザースペースを実行していますか?

いずれにせよ、プログラムを実行して、straceどのシステムコールが作成されているかを確認してみませんか?それはほぼ確実に問題をすぐに解決します。

于 2012-06-10T04:33:11.910 に答える
4

私はついに問題を見つけました!!! #include <unistd.h>正しい lseek() を使用するために配置する必要があります。unistd.hただし、予期しない動作が発生するにもかかわらず、コンパイル可能である理由がわかりません。関数のプロトタイプを含めないと、コンパイルもできないはずだと思いました。

このコードは、Jon Erickson によるHacking: The Art of Exploitation 2nd Edition#include <unistd.h>に書かれています。

于 2012-06-18T01:23:46.377 に答える
1

初期変数長が 34 に設定されている場合、上記のコードは cur_position 5 を生成します (そのため、lseek 関数が戻った後に少なくとも 34 バイトが存在することは間違いありません)。

エラーを発生させずにファイルの終わりを超えてシークすることができるため、これは必ずしもそうではありません。

lseek()以下の の man ページからの抜粋を参照してください。

lseek() 関数を使用すると、ファイル オフセットをファイルの末尾を超えて設定できます (ただし、ファイルのサイズは変更されません)。

lseek()そのため、まだファイルの末尾を超えている ing を形成する値を受け取ることができます。したがってread()、この位置から ing を実行しても 0 が返されます (ファイルの終わりを超えているため)。


また、正しい型 (使用されるメソッドで使用される型) を使用することにもっと注意を払うことは悪い考えではないという R.. に同意します。


更新: また、呼び出すシステム関数のすべてのヘッダーを含めるように注意することもできます。そのようなことを確認するには、 s オプションを使用してすべてのコンパイラ警告をオンにすることを強くお勧めします。それらは無料です... ;-)gcc-Wall

于 2012-06-10T10:46:46.910 に答える