Skip to content

Commit 6959466

Browse files
Fix deadly-signal crash in CSV segmenter (#718)
Summary: Pull Request resolved: #718 The CSV segmenter crashed (fatal assertion) when processing input with high token density (e.g., many consecutive separators). The root cause was twofold: 1. `maxNumTokens` was calculated as `min(byteSize, chunkByteSizeMax)`, assuming at most 1 token per byte. But consecutive separators produce 2 tokens per byte (empty field + separator), causing the lexer to exhaust the token buffer before consuming enough bytes. 2. When the token buffer was exhausted mid-chunk, the segmenter's internal consistency checks fired with `logicError`, which triggers a fatal assertion in `ZL_E_create_va` ("Logic errors should never actually be generated"). Fix: - Increase `maxNumTokens` to `2 * chunkSize + 1` to handle worst-case token density Reviewed By: Victor-C-Zhang Differential Revision: D103001388 fbshipit-source-id: 8fe4b418b25b551ea76a68a846f9150c59e09f44
1 parent 994db72 commit 6959466

1 file changed

Lines changed: 15 additions & 7 deletions

File tree

custom_parsers/csv/csv_segmenter.c

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -113,10 +113,11 @@ static ZL_Report SEGM_csv(ZL_Segmenter* sctx)
113113
useNullAwareParse,
114114
tryGetIntParam(sctx, ZL_PARSER_USE_NULL_AWARE_PID));
115115

116-
const size_t maxNumTokens = ZL_MIN(byteSize, chunkByteSizeMax);
117-
ZL_ERR_IF_GE(
118-
maxNumTokens, 1u << 30, node_invalid_input, "chunk size too big");
119-
ZL_CSV_TokenType* types = ZL_Segmenter_getScratchSpace(
116+
const size_t chunkSize = ZL_MIN(byteSize, chunkByteSizeMax);
117+
ZL_ERR_IF_GE(chunkSize, 1u << 30, node_invalid_input, "chunk size too big");
118+
// Each byte can produce up to 2 tokens (empty field + separator/newline).
119+
const size_t maxNumTokens = 2 * chunkSize + 1;
120+
ZL_CSV_TokenType* types = ZL_Segmenter_getScratchSpace(
120121
sctx, maxNumTokens * sizeof(ZL_CSV_TokenType));
121122
ZL_ERR_IF_NULL(types, allocation);
122123
uint32_t* sizes =
@@ -153,11 +154,18 @@ static ZL_Report SEGM_csv(ZL_Segmenter* sctx)
153154
node_invalid_input,
154155
"CSV is not well formed: No newline found");
155156
const char* const end = lexer.src;
156-
ZL_ERR_IF_EQ(numTokens, 0, logicError);
157+
ZL_ERR_IF_EQ(numTokens, 0, logicError, "CSV lexer produced no tokens");
157158
if (end != lexer.end) {
158-
ZL_ERR_IF_LT((size_t)(end - begin), chunkByteSizeMax, logicError);
159+
ZL_ERR_IF_LT(
160+
(size_t)(end - begin),
161+
chunkByteSizeMax,
162+
logicError,
163+
"CSV chunk consumed fewer bytes than expected");
159164
ZL_ERR_IF_NE(
160-
types[numTokens - 1], ZL_CSV_TokenType_Newline, logicError);
165+
types[numTokens - 1],
166+
ZL_CSV_TokenType_Newline,
167+
logicError,
168+
"CSV chunk does not end with a newline");
161169
}
162170
ZL_ERR_IF_ERR(SEGM_csvProcessChunk(
163171
sctx,

0 commit comments

Comments
 (0)