From c9cf6dfdfff51e721bfedbd155011b340ef92348 Mon Sep 17 00:00:00 2001 From: Scott Claiborne Date: Thu, 20 Aug 2026 09:16:48 -0700 Subject: [PATCH] Fix page fault when file size exceeds MaxFileSize ReadBuffer was allocated at exactly IN.CFG.MaxFileSize bytes but its contents are consumed as a C string by strtok_r in csvProcessData(). FIOWrap passes IN.PAR.len straight through to FileRead with no clamp, so a file at or above MaxFileSize filled the buffer completely, leaving no terminator. Parsing then ran off the end of the allocation and the target took a page fault. - csvInitBuffer(): allocate one extra byte so a completely full buffer is still a valid string. MaxLength still holds the usable payload length, so all existing overflow checks are unchanged. - csvClearBuffer(): clear the guard byte as well. - CSVFn_Cyclic(), CSV_ST_OPEN: compare FIOWrap.OUT.STAT.FileLen against ReadBuffer.MaxLength before touching the data. An oversized file now reports CSV_ERR_BUFFERFULL ("Maximum file size reached. Check IN.CFG.MaxFileSize.") instead of parsing truncated data. On success, record CurrentLength and terminate the buffer explicitly rather than relying on leftover zeros from the last clear. Verified by compiling the example project's CSVFileLib against AS6. Co-Authored-By: Claude Opus 5 --- src/Ar/CSVFileLib/ANSIC.lby | 2 +- src/Ar/CSVFileLib/CHANGELOG.md | 5 +++++ src/Ar/CSVFileLib/CSVFn_Cyclic.c | 21 +++++++++++++++++++++ src/Ar/CSVFileLib/csvClearBuffer.c | 2 +- src/Ar/CSVFileLib/csvInitBuffer.c | 5 ++++- 5 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/Ar/CSVFileLib/ANSIC.lby b/src/Ar/CSVFileLib/ANSIC.lby index 85226c0..f9b3fa5 100644 --- a/src/Ar/CSVFileLib/ANSIC.lby +++ b/src/Ar/CSVFileLib/ANSIC.lby @@ -1,6 +1,6 @@  - + CSVFileLib.typ CSVFileLib.var diff --git a/src/Ar/CSVFileLib/CHANGELOG.md b/src/Ar/CSVFileLib/CHANGELOG.md index 49f37dc..f5250ef 100644 --- a/src/Ar/CSVFileLib/CHANGELOG.md +++ b/src/Ar/CSVFileLib/CHANGELOG.md @@ -1,3 +1,8 @@ +2.0.1 - Fix page fault when the file being read is larger than IN.CFG.MaxFileSize + Read buffers now allocate one extra byte so a completely full buffer is still a + valid string, and CSV_ST_OPEN reports CSV_ERR_BUFFERFULL instead of parsing a + truncated file + 2.0.0 - Migrate to Automation Studio 6 1.2.5 - Fix critical bug introduced in 1.2.4 diff --git a/src/Ar/CSVFileLib/CSVFn_Cyclic.c b/src/Ar/CSVFileLib/CSVFn_Cyclic.c index ddbdbf6..3fd7d9c 100644 --- a/src/Ar/CSVFileLib/CSVFn_Cyclic.c +++ b/src/Ar/CSVFileLib/CSVFn_Cyclic.c @@ -588,6 +588,27 @@ switch( t->OUT.STAT.State ){ t->Internal.FIOWrap.IN.CMD.Open= 0; + + /* The file did not fit in the read buffer. FIOWrap passes IN.PAR.len straight + to FileRead, so the buffer is filled completely and the data is truncated + mid-file. Do not parse it. */ + + if( t->Internal.FIOWrap.OUT.STAT.FileLen > t->Internal.ReadBuffer.MaxLength ){ + + csvSetError( (UINT)CSV_ERR_BUFFERFULL, t ); + + break; + + } + + + /* Record how much was actually read and terminate the buffer for parsing */ + + t->Internal.ReadBuffer.CurrentLength= t->Internal.FIOWrap.OUT.STAT.FileLen; + + *(char*)(t->Internal.ReadBuffer.pData + t->Internal.ReadBuffer.CurrentLength)= '\0'; + + t->Internal.LineNumber= 0; t->Internal.SuccessfulLineCount= 0; diff --git a/src/Ar/CSVFileLib/csvClearBuffer.c b/src/Ar/CSVFileLib/csvClearBuffer.c index 42dcbe5..2868b8c 100644 --- a/src/Ar/CSVFileLib/csvClearBuffer.c +++ b/src/Ar/CSVFileLib/csvClearBuffer.c @@ -52,7 +52,7 @@ if( pBuffer == 0 ){ pBuffer->CurrentLength= 0; -memset( (void*)pBuffer->pData, 0, pBuffer->MaxLength ); +memset( (void*)pBuffer->pData, 0, pBuffer->MaxLength + 1 ); return 0; diff --git a/src/Ar/CSVFileLib/csvInitBuffer.c b/src/Ar/CSVFileLib/csvInitBuffer.c index b05d88a..88dfc9d 100644 --- a/src/Ar/CSVFileLib/csvInitBuffer.c +++ b/src/Ar/CSVFileLib/csvInitBuffer.c @@ -56,7 +56,10 @@ if( (BufferLength == 0) memset( pBuffer, 0, sizeof(CSVFileMgr_Int_Buffer_typ) ); -if( TMP_alloc( BufferLength, (void **)&(pBuffer->pData) ) != 0 ) return CSV_ERR_MEMALLOC; +/* Allocate one extra byte so that a completely full buffer is still a valid C string. + MaxLength stays at BufferLength, so all overflow checks remain unchanged. */ + +if( TMP_alloc( BufferLength + 1, (void **)&(pBuffer->pData) ) != 0 ) return CSV_ERR_MEMALLOC; pBuffer->MaxLength= BufferLength;