我有一个包含3个染色体字符串的文件,我想把它连接到一个基因组中。然后,我必须跨多个线程访问这个连接字符串(我使用pthread_t)。为此,我必须在提取数据时使用pthread_mutex_lock,然后使用strcat连接使用const *函数fai_fetch提取的数据,然后将数据保存为char* (参见下文)。
// genome_size the size of all the chromosomes together
// chr_total the number of chromosomes I wish to concatenate
char* genome = (char*) malloc(sizeof(char) * (genome_size+chr_total));
for (int i = 0; i < chr_total; i++){
pthread_mutex_lock(&data_mutex);
const char *data = fai_fetch(seq_ref,chr_names[i],&chr_sizes[i]);
pthread_mutex_unlock(&data_mutex);
//sprintf(&genome[strlen(genome)],data);
strcat(genome,data);
//sprintf(genome+strlen(genome),data); //All three gives conditional jump or move error
//sprintf(genome,data); // THIS SOLVES VALGRIND ISSUE ONE BUT DOES NOT GIVE A CONCATENATED CHAR*
}所有这些都很有效,但是我得到了
条件跳转或移动取决于引用“strcat(基因组,数据)”的未初始化值;
未初始化的值是通过引用"char*基因组= (char*) malloc(sizeof(char) *(genome_size+chr_total))“的堆分配来创建的;
在其他StackOverflow答案的基础上,我尝试了sprintf(&genomestrlen(基因组),data)和sprintf(genome+strlen,data);而不是strcat。然而,他们也给出了同样的英勇的信息。
唯一能缓解这一错误的方法是使用sprintf(基因组,数据);然而,我不会得到完整的基因组,而只是一个染色体。
尝试基因组+= sprintf(基因组,数据);给我./a.out':munmap_chunk():无效指针和./a.out':free()
关于“未经初始化的值是由堆分配创建的”错误->,那么我的问题是,只有在所有线程运行完之后,我才能释放该内存。因此,当我使用malloc时,我不知道如何初始化堆分配中的值。
有可能解决这些具体的价值错误吗?
发布于 2021-10-01 10:20:50
使用Val差伦来定位问题代码
“条件跳转或移动取决于未初始化的值”消息意味着Val差尔已经确定程序的某些结果依赖于未初始化的内存。使用--track-origins=yes标志跟踪未初始化值的来源。也许能帮你找到那个价值。来自man 1 valgrind
当
设置为yes时,Memcheck会跟踪所有未初始化值的起源。然后,当报告未初始化的值错误时,Memcheck将尝试显示值的来源。源可以是以下四个位置之一:堆块、堆栈分配、客户端请求或其他杂项源(例如,对brk的调用)。
更具体地说,在您的程序中:
问题1:使用未初始化的genome
线
char* genome = (char*) malloc(sizeof(char) * (genome_size+chr_total));使用genome分配malloc(2)缓冲区,然后在以下文件中使用该缓冲区:
strcat(genome,data);请注意,像strlen(3)和strcat(3)这样的函数在C-字符串上工作,它们是以空字符('\0')终止的缓冲区。
malloc(2)只是分配内存,而不对其进行初始化,因此您分配的缓冲区可能包含任何值(并被认为是未初始化的)。您应该避免将字符串相关函数与未初始化的缓冲区一起使用,因为它会导致未定义的行为。
幸运的是,calloc(2)这样做了--它分配缓冲区并将其所有位初始化为零,从而得到一个有效的0长度C-字符串,您可以对其进行操作。我建议使用以下修复方法来确保初始化genome:
char* genome = calloc(genome_size+chr_total+1, sizeof(char));还请注意,我已经将+1添加到分配缓冲区的长度中。这样做是为了确保结果的genome将以空终止符结尾(假设genome_size+chr_total是从fai_fetch返回的所有缓冲区的总大小)。
还请注意,就性能而言,calloc比malloc慢一点(因为它初始化了数据),但在我看来,它初始化整个缓冲区更安全。就特定程序而言,可以通过使用malloc并仅初始化第一个字节来节省性能负担:
char* genome = malloc(sizeof(char) * (genome_size + chr_total + 1));
if (NULL == genome) {
perror("malloc of genome failed");
exit(1);
}
// So it will be a valid 0 length c-string
genome[0] = 0;我们不必将最后一个字节初始化为0,因为strcat为我们编写了终止空字符。
(潜在)问题2:在strcat中使用潜在的非空终止strcat
正如您在问题中所描述的,fai_fetch提取了一些数据:
const char *data = fai_fetch(seq_ref,chr_names[i],&chr_sizes[i]);然后在strcat行中使用它:
strcat(genome,data);正如我前面所写的,由于您使用的是strcat,所以data也应该以空结尾。
我不知道fai_fetch是如何实现的,但是如果它返回一个有效的C-字符串,那么您就可以了。
如果没有,那么您应该使用strncat,它可以工作在非空终止的缓冲区上。
来自man 3 strcat
strncat()函数类似,只是
我建议采取以下办法:
// I'm not sure what type `&chr_sizes[i]` is, assuming it's `size_t`
size_t length = &chr_sizes[i];
const char *data = fai_fetch(seq_ref,chr_names[i], length);
// Use strcat
strncat(genome, used_data, length); https://stackoverflow.com/questions/69401709
复制相似问题