• ベストアンサー

fscanf(),scanf()とBuffer Overflow

jactaの回答

  • jacta
  • ベストアンサー率26% (845/3158)
回答No.10

せっかくですので、もう少し考察してみましょう。 scanf("%10ls", wcs); のような場合には、どこまで読み込まれたのかを知るのは結構大変です。 特に、不正列によって走査が中断されると、検出するのはかなり難しくなります。少なくとも、MB_CUR_MAXバイトまでは先読みしないといけないわけですが、ungetcで戻せるのは1文字までしか保証されないのも厄介です。 やってやれないことはないでしょうが、かなりのボリュームになってしまいそうです。 scanf系の関数でどうしようもないのは、バッファオーバーフローよりむしろ数値のオーバーフローです。 入力された値が、実引数で指定したオブジェクトで表現できなかった場合の動作は未定義なので、数値がオーバーフローした時点で、一見動いているように見えても、安全性・信頼性の観点からは既に終わってしまっています。 というわけで、上記のような場合は、scanf系関数はsscanfも含めて、安全とはいえないでしょうね。

mac_res
質問者

お礼

ありがとうございます。 sscanf(3)にも危険性はあるという指摘、大変興味深いです。 scanf()系の関数は、大変便利なのでつい使いたくなりますが、どういう仕様だったらもっと安全だったのでしょうねえ。

関連するQ&A

  • scanf()関数の使い方について

    はじめまして。 質問があります。 以下のコードを見てください。 ---------------------------------------------------------------- #include <stdio.h> #include <stdlib.h> int main(void) { int i; char buf[256]; int y; int m; int d; printf("文字列を入力してください:"); scanf("%s",buf); i = sscanf(buf,"%d/%d/%d",&y,&m,&d); //OK #if 0 i = sscanf(buf,"%d %d %d",&y,&m,&d); //NG #endif printf("日付 %d-%d-%d 戻り値i=%d\n",y,m,d,i); return EXIT_SUCCESS; } ---------------------------------------------------------------- 標準入力から日付を表す文字列「例:"2007/04/17"」を入力してbufに 格納したものをsscanf関数の第1引数に指定して、y,m,dを表示 させてみると、「i = sscanf(buf,"%d/%d/%d",&y,&m,&d)」では、 うまくyとmとdに日付が格納される(つまり、yに2007が入り、mには 04が入り、dには17が入る。)のですが、 「i = sscanf(buf,"%d %d %d",&y,&m,&d);」でbufに格納すると、 yにはうまく格納されるのですが、他のmとdには、うまく格納してくれ ません。これは、なぜなのでしょうか? ご教授お願いします。

  • fgetsとsscanf

    C言語の勉強をしております。 初歩的な質問なのかもしれないですが、 char buf[80]; char data[32]; fgets(buf,sizeof(buf),stdin); sscanf(data, "%s", buf); と、 fgets(data, sizeof(buf), stdin); は何が違うのでしょう? 他の質問内容やネットで探してみたんですが、基本的には組み合わせて使用されているみたいなんですが、必要性がわかりません・・・。 例えば、fgetsで構造体のメンバ(文字配列)へキーボードからデータを入力したい場合は、どちらで行うのが良いのでしょう? また、入力データが未入力かどうか判断させるには、 fgets(buf,sizeof(buf),stdin); if(buffer[0] == '\n'){   /* ループを抜ける */   break; } で良いですよね? ※関連している質問 http://oshiete1.goo.ne.jp/qa4438371.html あと、同じ処理内で、getsやscanfを混同して使用すると、どこかの入力時に改行がバッファに残ってしまい、入力処理が飛ばされてしまいますか? 以上、よろしくお願いいたします。

  • 一番大きい奇数を表示する

    scanf関数を使用して、文字列を10回入力し一番大きい文字列を表示するプログラムを作ったのですが、 一番大きい「奇数」を表示するように条件を加えた場合どうすればよいのでしょうか? 偶数=割り切れる 奇数=割り切れない ということまでは分かるのですがその先が分かりません。 一応一番大きい文字列を表示するプログラムを貼っておきます。 #include <stdio.h> int main(void) { char str[1024]; char buf[10]; int i; printf("文字列を10回入力して下さい:\n"); memset(str, 0, sizeof(str)); for (i = 0; i < 10; i++) { memset(buf, 0, sizeof(buf)); printf("input>\n"); scanf("%s", buf); } if (strcmp(buf, str) > 0) { strcpy(str, buf); } printf("output>\n%s\n" , str); getchar(); }

  • scanf("%s", buf);でスペースを含んだ文字

    コンソールプログラムで scanf("%s", buf); を使用してユーザに入力された文字によって処理を行いたいのですが、このままではスペースを含む文字列がスペースの手前で切られてしまいます。 C:\Program Filesなどを入力可能にさせたい場合にはどのようにするのがベターですか?

  • fgets, sscanf, バッファ、ストリーム について

    ファイルからデータを入力するのに、fscanf の代わりに fgets と sscanf を用いようと考えています。 そこで、sscanf に与えるバッファ文字列を、ファイルストリームのように扱う方法は無いものでしょうか。 例えば以下のデータファイルに対して、以下のプログラムをうまく動作させるには、どのようにすればよいでしょうか。 どうぞ、よろしくお願いします。 (データファイル test.dat) n_data 4 1 3 8 4 (プログラム) #include <stdio.h> main() { int i, n_data, *data; char buf[100]; FILE *fp; fp = fopen ( "test.dat", "r" ); fgets(buf, 100, fp); sscanf( buf, "n_data %d\n", &n_data ); data = (int *)malloc( n_data * sizeof(int) ); for( i=0; i<n_data; i++ ){ fgets(buf, 100, fp); sscanf( buf, "%d", &(data[i]) ); } sscanf( buf, "\n" ); close( fp ); printf( "n_data %d\n", n_data ); for( i=0; i<n_data; i++ ) printf( " %d", data[i] ); printf( "\n" ); } ちなみに、2行の fgets(buf, 100, fp); をコメントアウトして、 "sscanf( buf," を "fscanf( fp," に変更するとうまく動作します。

  • scanfについて

    こんにちわ。 今Cのプログラムを勉強しているんですが, puts("入力します:"); if (fscanf(stdin,"%s", name) == EOF) { puts("エラーです"); } では,改行のみの場合に,何も返さずにもう一度fscanfが読み込まれますよね。 (fscanfは改行のみの場合はそれ自身の関数が再度呼ばれると思うんですが・・・) これを改行もエラーとして表示するにはどうすればよろしいでしょうか。 ただし,入力文字は2文字以上です。 他の入力関数を用いることになってもいいんですが,わかる方,よろしくおねがいします。

  • 一番大きい奇数を表示する

    scanf関数を使って数字を10回入力して一番大きなものを表示させるプログラムをつくったのですが、 さらに一番大きな奇数を表示するにはどうすればいいのでしょうか? 偶数=割り切れる 奇数=割り切れない というところまでは分かるのですが、以下のプログラムに奇数を判別するソースを追加するのにはどうすればいいのでしょうか。 #include <stdio.h> int main(void) { char str[1024]; char buf[10]; int i; int w; printf("文字列を10回入力して下さい:\n"); memset(str, 0, sizeof(str)); for (i = 0; i < 10; i++) { memset(buf, 0, sizeof(buf)); printf("input>\n"); scanf("%s", buf); } for (i = 0; i < 10; i++) { if ((buf[i] & 1) == 1) /* 奇数であるか */ { if (strcmp(buf, str) > 0) { strcpy(str, buf); } } } printf("output>\n%s\n" , str); getchar(); }

  • scanf関数について

    scanf関数で、下記のように書いたとき char ss[10]; scanf("%s", ss); printf("ss=%s\n", ss); ssは9文字までしかはいりませんが、入力時に10文字以上入力したら、prinitf関数でちゃんと入力した(10文字以上)の文字を表示してくれました。 これは、ssの容量を越えた分のメモリを確保してくれているのですか?

  • fgetsとsscanfを使って一行から複数入力

    環境はC言語です。 一行から不定数の文字列を入力したいと考えています。 fscanfは使わずに、fgetsとsscanfを使って実現させたいと考えています。 以下ではうまくいきませんでした。 --sorce-- char temp[1024], buf[1024]; while(fgets(stdin, 1024, buf) != NULL)){    //ファイルで標準入力でもどっちも可能  while(sscanf(buf, "%s",temp) != EOF){   printf("%s ", temp);  } } --input-- red blue black yellow white red red red black yellow white blue red blue blue --理想output-- red blue black yellow white red red red black yellow white blue red blue blue よろしくおねがいします。

  • fgets関数とscanfについて

    fgets関数とscanfの意味が似ていると思うんですが、違いは何ですか? 例えば、fgets( str, 81, stdin ) は変数strに80文字制限で、標準入力から入力するという意味ですよね? scanf("%s",s)は変数sに文字列を入力するという意味ですよね? 意味が似てると思うんですが、実際は何が違うんでしょうか? 回答よろしくお願いします。