2

長い文字列が渡された場合、以下のコードで二重に解放されます。いろいろやってみました。free(s) 行を削除すると、それは消えます。なぜそれが起こっているのか分かりません。

void format_str(char *str1,int l,int o) {
    char *s = malloc(strlen(str1)+1);
    char  *s1=s, *b = str1;
    int i=0;
    while(*str1!='\0') {
        i++;
        *s1++=*str1++;

        if(i>=l) {
            if(*str1!=',') {
                continue;
            }
        *s1++=*str1++;
            *s1++='\n';
            for(i=0;i<o;i++) {
                *s1++=' ';
            }
            i = 0;
        }
    }
    *s1 = '\0';
    strcpy(b,s);
    free(s);
}
4

5 に答える 5

5

sコピーするデータの量に対して十分なスペースを割り当てていない可能性があります。あなたのロジックが実際に何をしているのかはわかりませんが、次のようなものがあります

        *s1++=*str1++;
        *s1++='\n';

から単一の文字に対して複数の文字をs(経由で) にコピーしている場合。s1str1

そして、計算可能なすべてのものを愛するために、より良い変数名を使用してください!

于 2012-09-20T00:38:30.477 に答える
0

他の人が指摘しているように、コードが割り当てられたメモリの最後を超えて書き込むため、ヒープメモリが破損する可能性が最も高くなります。

メモリが破損しているかどうかを確認するのは簡単です。関数の先頭で、str1 の長さを保存します。名前を「len_before」にしましょう。free() を呼び出す前に、文字列の長さを再度取得し、「len_after」という名前を付けましょう。

(len_after > len_before) の場合、致命的なエラーが発生します。

比較的単純な修正方法は、str1 が最大長になるまでの最大長を渡し、その量のメモリを malloc し、最大長を超える前に停止することです。つまり、null で切り捨てますが、制限内にとどめます。

int len_before, len_after;

len_before = strlen(str1) + 1;
.
. /* Rest of the code. */
.
len_after = strlen(str1) + 1;
if (len_after > len_before) {
    printf("fatal error: buffer overflow by %d bytes.\n", len_after - len_before);
    exit(1);
}
free(s);
于 2012-09-30T05:40:10.733 に答える
0

ほとんどの場合、ヒープが破損しています。例えば:

int main() 
{
    char original[1000] = "some,,,string,,, to,,,,format,,,,,";

    printf( "original starts out %u characters long\n", strlen(original));
    format_str( original, 6, 6);
    printf( "original is now %u characters long\n", strlen(original));

    return 0;
}

によって割り当てられたバッファは、サイズmalloc()よりもはるかに大きくする必要がありstrlen(str1)+1ます。具体的には、少なくとも 63 バイトの長さである必要があります (関数は質問でコーディングされているため、割り当てのサイズは 35 バイトです)。

より具体的なヘルプが必要な場合は、何をしようとしているのかを説明する必要があります (パラメーターは何のlためにあるoのか? など)。

于 2012-09-20T01:23:48.493 に答える
0

メンタルヘルスのために、コードを再フォーマットし、変数の名前を推測で変更してみます。

void format_str(char *str, int minlen, int indent) 
{
    char *tmpstr = malloc( strlen(str) + 1 ); // here is the problem
    char *wrkstr = tmpstr, *savestr = str;
    int count = 0;

    while ( *str != '\0' ) {
        count++;
        *wrkstr++ = *str++;

        if ( count >= minlen ) {

            if ( *str != ',' ) {
                continue;
            }

            *wrkstr++ = *str++;
            *wrkstr++ = '\n';
            for ( count = 0;  count < indent;  count++ ) {
                *wrkstr ++= ' ';
            }
            count = 0;
        }
    }

    *wrkstr = '\0';
    strcpy(savestr,tmpstr);
    free(tmpstr);
}

他の人が指摘しているように、一時文字列に十分なスペースを割り当てていません。

コードには他に 2 つの問題があります (そのうちの 1 つは重大な問題です)。

strおそらく、それがそうでなくNULL、おそらくそれminlenでありindent、否定的でないことを確認して、引数を検証する必要があります。これは重要ではありませんが、NULLstr は segfault (標準ライブラリの文字列関数と同じ動作) であり、1 未満の値はminlenおよび/またはindent0 であるかのように動作するためです。

主な問題は、 にどれだけのスペースがあるかですstr。フォーマット中にやみくもに文字列を大きくしてから、同じメモリにコピーして戻します。strこれは、発生するのを待っているバッファ オーバーフローです (特にスタックを指している場合は、セキュリティに深刻な影響を与える可能性があります)。

それを修正するには:

  • 十分なスペースを割り当てる必要があります。

  • 割り当てられた文字列を返し、呼び出し元がそれを解放する責任があることを規定するか (strdupそうするように)、使用可能なスペースを指定するパラメーターを追加してstrから、書式設定された文字列を格納するのに十分でない場合は作業を回避する必要があります。

于 2012-09-20T02:23:38.480 に答える
0

このユースケースは、予行演習を行う可能性が必要であることの良い例です。

次のようにコードを変更することをお勧めします。

ssize_t format_str(const char * input, int p1, int p2, char * output);

òutput1 ターゲット バッファは、関数に渡されるパラメータを介して関数の呼び出し元によって提供されます。

2 関数は、ターゲット バッファに書き込まれた文字数を返します (負の値は、何らかのエラーを示している可能性があります)。

3 渡された値outputが NULL の場合、関数は何もコピーせinput、参照されているデータを解析し、ターゲット バッファに書き込まれる文字数を決定し、この値を返します。

次に、変換関数を使用するには、次のように 2 回呼び出します。

char * input = "some,,test   , data,,, ...";
int p1 = <some value>, p2 = <some other value>;
ssize_t ssizeOutput = format_str(input, p1, p2, NULL)
if (0 > ssizeOutput)
{
  exit(EXIT_FAILURE);
}
else if (0 < ssizeOutput)
{
  char * output = calloc(ssizeOutput, sizeof(*output));
  if (!output)
  {
    exit(EXIT_FAILURE);
  }

  ssizeOutput = format_str(input, p1, p2, output);
  if (0 > ssizeOutput)
  {
    exit(EXIT_FAILURE);
  }
}
于 2012-09-20T08:09:23.947 に答える