【问题标题】:String Allocated with malloc Enaccessible after Function Return函数返回后使用 malloc 分配的字符串可访问
【发布时间】:2018-10-14 02:29:06
【问题描述】:

我遇到了一个奇怪的错误,我终其一生都无法弄清楚。我有一个函数可以根据另一个编码函数将字节数组解码为字符串。解码的函数大致是这样的:

char *decode_string( uint8_t *encoded_string, uint32_t length,
    uint8_t encoding_bits ) {
        char *sequence_string;
        uint32_t idx = 0;
        uint32_t posn_in_buffer;
        uint32_t posn_in_cell;
        uint32_t encoded_nucleotide;
        uint32_t bit_mask;

        // Useful Constants
        const uint8_t CELL_SIZE = 8;
        const uint8_t NUCL_PER_CELL = CELL_SIZE / encoding_bits;

        sequence_string = malloc( sizeof(char) * (length + 1) );
        if ( !sequence_string ) {
            ERR_PRINT("could not allocate enough space to decode the string\n");
            return NULL;
        }
        // Iterate over the buffer, converting one nucleotide at a time.
        while ( idx < length ) {
            posn_in_buffer = idx / NUCL_PER_CELL;
            posn_in_cell = idx % NUCL_PER_CELL;
            encoded_nucleotide = encoded_string[posn_in_buffer];
            encoded_nucleotide >>= (CELL_SIZE - encoding_bits*(posn_in_cell+1));
            bit_mask = (1 << encoding_bits) - 1;
            encoded_nucleotide &= bit_mask;
            sequence_string[idx] = decode_nucleotide( encoded_nucleotide );
                // decode_nucleotide returns a char on integer input.
            idx++;
        }
        sequence_string[idx] = '\0';
        printf("%s", sequence_string);    // prints the correct string
        return sequence_string;
}

错误是返回指针,如果我尝试打印它,会导致分段错误。但是在函数内部调用printf("%s\n", sequence_string) 将打印所有内容。如果我这样调用函数:

const char *seq = "AA";
uint8_t *encoded_seq;
encode_string( &encoded_seq, seq, 2, 2);
char *decoded_seq = decode_string( encoded_seq, 2, 2);

if ( decoded_seq ) {
    printf("%s\n",decoded_seq);    // this crashes
    if ( !strcmp(decoded_seq, seq) ) {
        printf("Success!");
}

然后它会在打印时崩溃。 一些注意事项,其他功能似乎都可以工作,我已经对它们进行了相当彻底的测试(即decode_nucleotideencode_string)。该字符串还在函数内部正确打印。只有在函数返回后它才会停止工作。 我的问题是,仅通过从函数返回指针可能导致该内存变为无效的原因是什么?提前致谢!

【问题讨论】:

  • 我会把它添加进去。但奇怪的是,它似乎做的一切都是正确的。解码后的字符串是正确的并且以空值结尾(即,如果初始字符串是“AA”并且我对其进行编码,然后对其进行解码,它就会给我“AA”,只要我在函数内打印它。
  • 为什么有一个额外的参数传递给printf?您实际上是否在检查 my_decoded_sequence 是否为 NULL ?你能放一个完全可测试的minimal reproducible example吗?即显示实际执行打印的代码outside
  • 我的问题是它与这个函数本身无关,你可以通过使用 mallocs & inits 一个长度字符串的函数来存根它来显示它。我相信较早的函数已经破坏了堆栈,或者 decode_核苷酸正在破坏堆栈,并且一些以前设置和将来依赖的寄存器会导致您的错误。请问printf()中“2”的作用是什么?
  • 请学习如何使用gdb。它有帮助。
  • @mevets 我认为你可能是对的。我将不得不尽可能多地退后一步。不幸的是,我目前无法分享很多代码。

标签: c pointers segmentation-fault


【解决方案1】:

声明中的第一个(不是那么重要,但是):

sequence_string = malloc( sizeof(char) * (length + 1) );

sizeof(char) 根据定义总是 == 1。所以语句变为:

sequence_string = malloc(length + 1); 

在您帖子的这一部分:

char *decoded_seq = decode_string( encoded_seq, 2, 2);

...由于我看不到您对decode_string 的实现,因此我只能假设您在返回之前如何验证其输出。但是,我确实理解您期望返回值包含 C 字符串的合法内容的值。我还可以假设,因为您正在处理编码和解码,所以输出类型可能是unsigned char。如果我是正确的,那么输出类型为 unsigned char is 0-255 的合法字符范围。

在将值发送到printf 语句之前,您没有检查输出。如果decoded_seq的内存地址的值恰好是0,(在unsigned char的范围内)你的程序就会崩溃。字符串函数不适用于空指针。

您应该验证 _decode_string_ 的返回发送它到printf

char *decoded_seq = decode_string( encoded_seq, 2, 2);
if(decoded_seq != NULL)
{
    ...

【讨论】:

  • 我相信那里应该分配内存。它在函数调用中分配给decode_string,然后返回指针。所以decoded_seq 的值应该是一个指向分配内存的指针,理论上是被解码的字符串。
  • @Grimey - 同意,我知道你在哪里创建了内存。但是我重新做了这个答案的内容,而是着重在使用之前检查decode_string的返回值的重要性。
猜你喜欢
  • 2017-06-09
  • 2013-03-05
  • 2020-07-19
  • 2021-05-31
  • 2017-01-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多