2004年09月07日
川俣晶の縁側ソフトウェア技術雑記total 6542 count

Windowsのwvsprintf APIで非常に長い文字列を扱った場合の挙動

Written By: 川俣 晶連絡先

 COM版BlatJのトラブル調査の中で、Windowsのwvsprintf APIで非常に長い文字列を扱った場合の挙動について調べる必要が生じたので、調べてみました。

 このAPIは、結果を受け取る文字列長さを指定する引数を持っておらず、仮に用意したバッファ以上の長さの文字列をフォーマットするように指定した場合、何が起こるかが問題となります。

ドキュメントを見よう! §

 wvsprintfのドキュメントを見ると以下のように書かれています。(2008/07/20追記。手前のリンクは切れています。現在見つかるwvsprintfのドキュメントはバッファ最大サイズの記述が無い版です)

パラメータ

lpOut

1 個のバッファへのポインタを指定します。関数から制御が返ると、このバッファに、書式化が終わった文字列が格納されます。バッファの最大サイズは、1,024 バイトです。

 というわけで、1024バイトが限界らしいと言うことが読み取れます。

 とはいえ、MSDN Library July 2004(日本語版)を見ると「バッファの最大サイズは、1,024 バイトです。」という記述が欠けているので注意が必要です。

実際に書いてみよう! §

 Visual Studio.NET 2003で、C++のコンソールアプリケーションとして、実際にこのAPIに長大な文字列を渡すプログラムを書いてみました。

wvsprintf001.cpp §

// wvsprintf001.cpp : コンソール アプリケーションのエントリ ポイントを定義します。

//

#include "stdafx.h"

void __cdecl test(LPCSTR format,...)

{

    TCHAR buf[2048];

    memset(buf,'!',sizeof(buf)/sizeof(TCHAR)-1);

    buf[2047] = '\0';

    printf( "before buf[1024]=%d\n", buf[1024] );

    printf( "before buf[1025]=%d\n", buf[1025] );

    wvsprintf( buf, format, (va_list)((&format)+1));

    printf( "after buf[1024]=%d\n", buf[1024] );

    printf( "after buf[1025]=%d\n", buf[1025] );

    printf( "length=%d\n", strlen(buf) );

    printf( "result=%s\n", buf );

}

int _tmain(int argc, _TCHAR* argv[])

{

    TCHAR testdata[2048];

    for( int i=0; i<sizeof(testdata)/sizeof(TCHAR)-1; i++ )

    {

        testdata[i] = (i % 26) + 'A';

    }

    testdata[2047] = '\0';

    test("Start %s end",testdata);

    return 0;

}

stdafx.h §

// stdafx.h : 標準のシステム インクルード ファイルのインクルード ファイル、または

// 参照回数が多く、かつあまり変更されない、プロジェクト専用のインクルード ファイル

// を記述します。

//

#pragma once

#include <iostream>

#include <tchar.h>

// TODO: プログラムに必要な追加ヘッダーをここで参照してください。

#include <windows.h>

stdafx.cpp §

// stdafx.cpp : 標準インクルードのみを含むソース ファイルです。

// wvsprintf001.pch は、プリコンパイル済みヘッダーになります。

//  stdafx.obj にはプリコンパイル済み型情報が含まれます。

#include "stdafx.h"

// TODO: このファイルではなく、STDAFX.H で必要な

// 追加ヘッダーを参照してください。

ちょっと意外な実行結果 §

 これを実行すると以下のようになります。

before buf[1024]=33

before buf[1025]=33

after buf[1024]=0

after buf[1025]=33

length=1024

result=Start ABCDEFGHIJKLMNOPQR (以下長いので略)

(実行はWindows XP SP2上で行いました)

 結論から言えば、1024バイト以上になるはずの要求に対して、wvsprintf APIは1024バイトの結果を生成し、1025バイト目に'\0'を書き込んで文字列を終端していることが分かりました。ちょっと意外な感じを受けましたが、1024バイト目ではなく、1025バイト目です。しかし、1026バイト目の値は変化しておらず、ここを書き換えてはいないことが推測できます。

 このことから、wvsprintf APIを安全に実行するには、1025バイトの出力バッファを与えればよく、1024バイトを超える結果は自動的に切りつめられる、と考えて良さそうです。

Facebook

キーワード【 川俣晶の縁側ソフトウェア技術雑記
【技術雑記】の次のコンテンツ
2004年
09月
14日
基本中の基本、ドキュメントには日付を入れましょう
3days 0 count
total 3085 count
【技術雑記】の前のコンテンツ
2004年
09月
06日
クラスの依存性を取り除くIoC(Inversion of Control)とDependency Injectionパターン
3days 0 count
total 3262 count

このコンテンツを書いた川俣 晶へメッセージを送る

[メッセージ送信フォームを利用する]

メッセージ送信フォームを利用することで、川俣 晶に対してメッセージを送ることができます。

この機能は、100%確実に川俣 晶へメッセージを伝達するものではなく、また、確実に川俣 晶よりの返事を得られるものではないことにご注意ください。

このコンテンツへトラックバックするためのURL

http://mag.autumn.org/tb.aspx/20040907164021
サイトの表紙【技術雑記】の表紙【技術雑記】のコンテンツ全リスト 【技術雑記】の入手全リスト 【技術雑記】のRSS1.0形式の情報このサイトの全キーワードリスト 印刷用ページ

管理者: 川俣 晶連絡先

Powered by MagSite2 Version 0.36 (Alpha-Test) Copyright (c) 2004-2021 Pie Dey.Co.,Ltd.