2

Pythonと統合しているCモジュールのコードの一部に、char **(文字列の配列)があります。これは繰り返し割り当てられ、割り当てられた文字列で埋められ、解放されて再度割り当てられます。一般的なパターンは、配列の新しいコンテンツを(リストとして)提供する特定の関数が(Pythonから)呼び出されると、文字列の配列を繰り返し処理し、各文字列を解放してから、配列自体を解放します。次に、新しいPythonリストの内容を保持するために配列を再度割り当て、保持する各文字列にメモリを割り当てます。

リスト内の文字列の1つを解放しようとすると、エラーが発生します。このエラーは決定論的です。プログラムの同じポイントにある同じ単語リストの同じ単語ですが、その単語または単語リストについて特別なことは何もありません。(これは["CCellEnv"、 "18"、 "34"]であり、他の多くの形式と似ています)文字列を割り当てるループにデバッグコードを追加してみました。エラーを生成する関数は次のとおりです。

static PyObject* py_set_static_line(PyObject* self, PyObject* args)
{
    int i;
    //Free the old values of the allocated variables, if there are any
    if (numStaticWords > 0)
    {
        for (i = 0; i < numStaticWords; i++)
        {
            printf("Freeing word %d = '%s'\n", i, staticWords[i]);
            free(staticWords[i]);
        }
        free(staticWords);
        free(staticWordMatches);
    }

    //Parse arguments
    PyObject* wordList;
    unsigned short numWords;
    PyObject* wordMatchesList;
    if (!PyArg_ParseTuple(args, "O!HO!", &PyList_Type, &wordList, &numWords, &PyList_Type, &wordMatchesList))
        return NULL;

    numStaticWords = numWords;
    if (numStaticWords > 0)
    {
        staticWords = malloc(sizeof(char*) * numStaticWords);
        staticWordMatches = malloc(sizeof(int) * numStaticWords);

        PyObject* wordObj;
        PyObject* matchObj;
        char* word;
        for (i = 0; i < numStaticWords; i++)
        {
            //wordList is the list of strings passed from Python
            wordObj = PyList_GetItem(wordList, i);
            word = PyString_AsString(wordObj); //word is "18" in the failing case

            //staticWords is the char** array of strings, which has already been malloc'd
            staticWords[i] = malloc(sizeof(char) * strlen(word));

            //Test freeing the word to see if it crashes
            free(staticWords[i]); //Crashes for one specific word

            staticWords[i] = malloc(sizeof(char) * strlen(word));
            strcpy(staticWords[i], word);

            matchObj = PyList_GetItem(wordMatchesList, i);
            if (matchObj == Py_None)
            {
                staticWordMatches[i] = -1;
            }
            else
            {
                staticWordMatches[i] = PyInt_AsLong(matchObj);
            }
        }
    }
    Py_RETURN_NONE;
}

したがって、どういうわけか、常にこの特定の文字列に対してのみ、メモリを割り当ててそれを配置し、すぐにそのメモリを解放するとエラーが発生します。文字列の実際のテキストはメモリにコピーされません。この不思議な行動の原因は何でしょうか?

4

1 に答える 1

8

ここ

staticWords[i] = malloc(sizeof(char) * strlen(word));
strcpy(staticWords[i], word);

0「文字列」の -termination を割り当てることができません。そのため、これらの文字配列を文字列として操作すると、未定義の動作が発生する可能性が高くなります。

このようにしてください:

{
  int isNull = !word;

  staticWords[i] = calloc(sizeof(*staticWords[i]), (isNull ?0 :strlen(word)) + 1);
  strcpy(staticWords[i], isNull ?"" :word);
}
于 2013-01-02T16:19:31.837 に答える