12

AIXでpython-kerberosをビルドしようとしています。kerberospw.cはasprintfの呼び出しを使用しますが、Googleが私に言っていることから、asprintfはAIXには存在しません。

http://www.koders.com/c/fidAA9B130D588302673A28B568430A83131B7734C0.aspx?s=windows.hを見ましたが、これはスタンドインasprintfを作成できるように見えますが、これがどこに行くのか、どのように行うのかわかりません。 #kerberospw.cに含めます。

koders.comの例または他のコードを使用してasprintfを「偽造」する方法はありますか?kerberospw.cに示されているようにasprintf関数を含めることはできますか?私はCコーダーではありませんが、

asprintf(char ** resultp、const char * format、...)

末尾にドットが付いている私には、有効な署名のようには見えません。kerberospw.cからの関連行は以下のとおりです

asprintf(&message、"%。* s:%。* s"、(int)result_code_string.length、
(char *)result_code_string.data、
(int)result_string.length、
(char *)result_string.data);

python-kerberosの作成者に連絡できることはわかっていますが、a)パッチを適用すると役立つと思います。また、b)asprintfを使用する他のソフトウェアが存在する可能性があります。回避策があると便利です。

4

4 に答える 4

21

これは、書式設定された文字列のメモリを保持するバッファを割り当てて返す関数ファミリーのasprintfバリエーションです。printfこれは、可変数の引数を持つ関数です (したがって、...有効な C コードである宣言内の )。ここに説明があります。

が正しく機能している場合は、比較的簡単に再実装できますvsnprintf(つまり、バッファが小さすぎてフォーマットされた文字列を保持できない場合はエラーを返します)。

これはそのような実装です:

#include <stdarg.h>

int asprintf(char **ret, const char *format, ...)
{
    va_list ap;

    *ret = NULL;  /* Ensure value can be passed to free() */

    va_start(ap, format);
    int count = vsnprintf(NULL, 0, format, ap);
    va_end(ap);

    if (count >= 0)
    {
        char* buffer = malloc(count + 1);
        if (buffer == NULL)
            return -1;

        va_start(ap, format);
        count = vsnprintf(buffer, count + 1, format, ap);
        va_end(ap);

        if (count < 0)
        {
            free(buffer);
            return count;
        }
        *ret = buffer;
    }

    return count;
}
于 2011-02-04T15:06:21.403 に答える
14

Sylvain答えに基づいて、ここに両方asprintf()を使用した簡単な実装をvasprintf()示します。一方が必要な場合は、通常、もう一方も必要になるためです。また、va_copy()C99 からのマクロを考えると、実装は簡単asprintf()ですvasprintf()。実際、varargs 関数を作成するときは、それらをペアにして、1 つは省略記号表記を使用し、もう 1 つは省略va_list記号の代わりに引数を使用すると便利な場合がよくあります。

これはコードにつながります:

int vasprintf(char **ret, const char *format, va_list args)
{
    va_list copy;
    va_copy(copy, args);

    /* Make sure it is determinate, despite manuals indicating otherwise */
    *ret = NULL;

    int count = vsnprintf(NULL, 0, format, args);
    if (count >= 0)
    {
        char *buffer = malloc(count + 1);
        if (buffer == NULL)
            count = -1;
        else if ((count = vsnprintf(buffer, count + 1, format, copy)) < 0)
            free(buffer);
        else
            *ret = buffer;
    }
    va_end(copy);  // Each va_start() or va_copy() needs a va_end()

    return count;
}

int asprintf(char **ret, const char *format, ...)
{
    va_list args;
    va_start(args, format);
    int count = vasprintf(ret, format, args);
    va_end(args);
    return(count);
}

これらの関数が提供されていないシステムでこれらの関数を使用する際の注意が必要な部分は、関数を宣言する場所を決定することです。理想的には、それらは にあり<stdio.h>ますが、その場合、それらを記述する必要はありません。したがって、これらの関数が で宣言されていない場合は、これらの関数を含む<stdio.h>が宣言する他のヘッダーが必要<stdio.h>です。そして、理想的には、コードがこれを半自動的に検出する必要があります。おそらくヘッダーは"missing.h"であり、含まれています(一部):

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif /* HAVE_CONFIG_H */

#include <stdio.h>
#include <stdarg.h>

#ifndef HAVE_ASPRINTF
extern int asprintf(char **ret, const char *format, ...);
extern int vasprintf(char **ret, const char *format, va_list args);
#endif /* HAVE_ASPRINTF */

また、このasprintf()の man ページには、エラーの場合、ポインターの戻り値は不確定であると記載されていることに注意してください。質問で参照されているものを含む他のマニュアルページは、エラー時に明示的に NULL に設定されていることを示しています。C 標準委員会のドキュメント ( n1337.pdf ) では、メモリ不足時のエラー動作が指定されていません。

  • asprintf() を使用する場合、関数が失敗した場合にポインターが初期化されると想定しないでください。
  • asprintf() を実装する場合は、エラー時にポインタが null に設定され、確定的な動作が得られるようにします。
于 2011-02-04T17:14:42.600 に答える
1

snprintf()ほとんどの場合、2 回呼び出さない実装です。他の回答に示されているように、インクルードと定義を省略しました。

当然のことながら、asprintf()を への呼び出しとして定義します。vasprintf()

int asprintf(char **dst, const char * pcFormat, ...)
{
va_list ap;

  va_start(ap, pcFormat);
  int len = vasprintf(dst, pcFormat, ap);
  va_end(ap);
  return len;
}

vsnprintf()オーバーフロー呼び出しが 2 回目の場合にのみ、事前に定義された適切なサイズにバッファーを割り当てます。その論理的根拠は、s*printf()関数が非常に重いと見なされ、メモリの割り当て超過が許容されることです。

int vasprintf(char **dst, const char * pcFormat, va_list ap)
{
  int len = 512;      /* Worked quite well on our project */
  int allocated = 0;
  va_list ap_copy;
  char *buff = NULL;

  while(len >= allocated) {
    free(buff);
    buff = malloc(len+1);
    if(buff) {
      allocated = len+1;
      va_copy(ap_copy, ap);
      len = vsnprintf(buff, len+1, pcFormat, ap_copy);
      va_end(ap_copy);
    }
    else   /* malloc() failed */
      return -1;
  }
  *dst = buff;
  return len;
}

編集realloc():安価なので、呼び出しを単純なものに置き換えましたmalloc()。オーバーフローの場合、内部の hidden があるため、free()/malloc()ペアのコストは低くなります。いずれにせよ、その後の呼び出しでバッファ全体を上書きするため、そのコピーには意味がありません。realloc()memcpy()vsnprintf()

于 2014-09-30T17:06:37.497 に答える