[英]Valgrind conditional jump ... error with PCRE2 JIT when reading from file
我有一個非常有趣的問題。
我想使用 PCRE2 及其 JIT function。任務很簡單:從文件中讀取行,並找到模式。
這是示例代碼:
#include <stdio.h>
#include <string.h>
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
int search(pcre2_code *re, unsigned char * subject) {
pcre2_match_data *match_data_real = pcre2_match_data_create_from_pattern(re, NULL);
size_t len_subject = strlen((const char *)subject);
int rc = pcre2_match(
re,
(PCRE2_SPTR)subject,
len_subject,
0,
0,
match_data_real,
NULL
);
pcre2_match_data_free(match_data_real);
return rc;
}
int main(int argc, char ** argv) {
unsigned char subject[][100] = {
"this is a foobar",
"this is a barfoo",
"this is a barbar",
"this is a foofoo"
};
pcre2_code *re;
PCRE2_SPTR pattern = (unsigned char *)"foo";
int errornumber;
PCRE2_SIZE erroroffset;
re = pcre2_compile(
pattern,
PCRE2_ZERO_TERMINATED,
0,
&errornumber,
&erroroffset,
NULL
);
pcre2_jit_compile(re, PCRE2_JIT_COMPLETE);
FILE *fp;
int s = 0;
while(s < 2) {
search(re, subject[s++]);
}
if (argc >= 2) {
fp = fopen(argv[1], "r");
if (fp != NULL) {
char tline[2048];
while(fgets(tline, 2048, fp) != NULL) {
search(re, (unsigned char *)tline);
}
fclose(fp);
}
}
pcre2_code_free(re);
return 0;
}
編譯代碼:
gcc -Wall -O2 -g pcretest.c -o pcretest -lpcre2-8
如您所見,在第 58 行我檢查是否給定了參數,代碼嘗試將其作為文件打開。
另外,正如您在第 49 行中看到的,我想使用 PCRE2 的 JIT。
該代碼也能正常工作,但我用 Valgrind 對其進行了檢查,發現了一個有趣的行為:
Conditional jump or move depends on uninitialised value(s)
and Uninitialised value was created by a stack allocation
,但它指向main()
。 命令: valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all --track-origins=yes -s./pcretest myfile.txt
valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all --track-origins=yes -s./pcretest
pcre2_jit_compile((*re), PCRE2_JIT_COMPLETE);
在第 55 行,然后一切正常,沒有任何 Valgrind 報告。 命令: valgrind --tool=memcheck --leak-check=full --show-leak-kinds=all --track-origins=yes -s./pcretest myfile.txt
Valgrind的相關output:
==31385== Conditional jump or move depends on uninitialised value(s)
==31385== at 0x4EECD1A: ???
==31385== by 0x1FFEFFFC1F: ???
==31385== Uninitialised value was created by a stack allocation
==31385== at 0x1090FA: main (pcretest.c:27)
...
==31385== HEAP SUMMARY:
==31385== in use at exit: 0 bytes in 0 blocks
==31385== total heap usage: 12 allocs, 12 frees, 13,486 bytes allocated
==31385==
==31385== All heap blocks were freed -- no leaks are possible
==31385==
==31385== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
==31385==
==31385== 1 errors in context 1 of 1:
==31385== Conditional jump or move depends on uninitialised value(s)
==31385== at 0x4EECD1A: ???
==31385== by 0x1FFEFFFC1F: ???
==31385== Uninitialised value was created by a stack allocation
==31385== at 0x1090FA: main (pcretest.c:27)
==31385==
==31385== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
在第 27 行有int main(...)
。
我想念什么?
觀察:
Valgrind 報告告訴您正在訪問的未初始化數據位於對main()
的初始調用的堆棧幀中。 然而,
即使您使用調試信息進行編譯,Valgrind 報告也不會暗示特定變量。 還,
該報告的錯誤堆棧跟蹤不提供函數名稱,也不會追溯到main()
。 而且當然,
當您禁用模式的 JIT 編譯時,不會報告錯誤。
顯然,該錯誤與 PCRE2 的 JIT 編譯器生成的機器碼有關。 如果您不執行 JIT 編譯,那么您將通過普通的匹配路徑獲得正確的操作。 如果您確實執行了 JIT 編譯,那么 JIT 生成的代碼就會被使用,並且該代碼會觸發 Valgrind 錯誤。 盡管如此,您可能會得到正確的匹配,但我不會依賴它來觸發觀察到的 Valgrind 錯誤的代碼。
我嘗試了您代碼的變體,發現該錯誤與函數search()
中對pcre2_match_data_create_from_pattern()
和pcre2_match()
的調用特別相關。 任何一個都會導致 Valgrind 報告錯誤。 但為什么錯誤只發生在對search()
的某些調用中?
這似乎是因為 JIT 編譯在main()
的棧幀中設置了數據結構,這些數據結構被執行if (argc > 2)
語句的主體破壞了。 這與我能夠通過在該塊中為變量tline
添加初始化程序來避免錯誤的事實是一致的:
char tline[2048] = {0};
我可以想象為什么這會產生影響的各種場景,所有這些都與 JIT 生成的代碼和編譯器生成的代碼如何操作堆棧指針有關。
就個人而言,發現這樣的問題可能會說服我遠離 PCRE 的 JIT 編譯器。 至少在我有證據表明模式匹配是我程序的性能熱點之前,我肯定會這樣做。 但是,如果您必須使用 JIT,那么這里有一些可能(或可能不會)幫助您避免麻煩的建議:
牢記“及時”:盡可能接近實際使用模式時執行 JIT。
不要假設 JIT 代碼是長期可行的。 特別是,在調用 JIT 編譯器的函數返回后使用它可能是不安全的,但即使那么久也可能不好。
在運行 JIT 編譯器的同一函數中(僅)使用 JIT 編譯的正則表達式。
使該功能盡可能簡單。
在開始時使用初始值設定項聲明該函數的所有局部變量。
徹底測試。
這似乎比解決您的特定示例代碼的問題所必需的要多,但它更普遍地旨在減少違反 JIT 所做假設的已編譯程序的橫截面。
這確實是高效使用SSE2造成的。 CPU-s 使用 1K 或更大的頁面到 map memory,因此與有效緩沖區相交的 16 字節對齊的 16 字節讀取始終有效。 然而,16 字節數據的某些部分可能永遠不會被初始化,但算法會忽略這些字節,因此隨機字節對任何計算都沒有影響。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.