Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 37 additions & 13 deletions src/main/java/com/epam/parso/impl/SasFileParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,13 @@ public final class SasFileParser {
*/
private static final int MAX_PAGE_LENGTH = 10000000;

/**
* Byte buffer used for skip operations.
* Actually the data containing in this buffer is ignored,
* because it only used for dummy reads.
*/
private static final byte[] SKIP_BYTE_BUFFER = new byte[4096];

static {
Map<Long, SubheaderIndexes> tmpMap = new HashMap<>();
tmpMap.put((long) 0xF7F7F7F7, SubheaderIndexes.ROW_SIZE_SUBHEADER_INDEX);
Expand Down Expand Up @@ -359,16 +366,40 @@ private void processSasFileHeader(String builderEncoding) throws IOException {
}

if (sasFileStream != null) {
skipBytes(sasFileProperties.getHeaderLength() - currentFilePosition);
currentFilePosition = 0;
}
}

/**
* Skip specified number of bytes of data from the input stream,
* or fail if there are not enough left.
*
* @param numberOfBytesToSkip the number of bytes to skip
* @throws IOException if the number of bytes skipped was incorrect
*/
private void skipBytes(long numberOfBytesToSkip) throws IOException {

long remainBytes = numberOfBytesToSkip;
long readBytes;
while (remainBytes > 0) {
try {
int bytesLeft = sasFileProperties.getHeaderLength() - currentFilePosition;
long actuallySkipped = 0;
while (actuallySkipped < bytesLeft) {
actuallySkipped += sasFileStream.skip(bytesLeft - actuallySkipped);
readBytes = sasFileStream.read(SKIP_BYTE_BUFFER, 0,
(int) Math.min(remainBytes, SKIP_BYTE_BUFFER.length));
if (readBytes < 0) { // EOF
break;
}
currentFilePosition = 0;
} catch (IOException e) {
throw new IOException(EMPTY_INPUT_STREAM);
}
remainBytes -= readBytes;
}

long actuallySkipped = numberOfBytesToSkip - remainBytes;

if (actuallySkipped != numberOfBytesToSkip) {
throw new IOException("Expected to skip " + numberOfBytesToSkip
+ " to the end of the header, but skipped " + actuallySkipped + " instead.");
}
}

Expand Down Expand Up @@ -893,14 +924,7 @@ private List<byte[]> getBytesFromFile(Long[] offset, Integer[] length) throws IO
if (cachedPage == null) {
for (int i = 0; i < offset.length; i++) {
byte[] temp = new byte[length[i]];
long actuallySkipped = 0;
while (actuallySkipped < offset[i] - currentFilePosition) {
try {
actuallySkipped += sasFileStream.skip(offset[i] - currentFilePosition - actuallySkipped);
} catch (IOException e) {
throw new IOException(EMPTY_INPUT_STREAM);
}
}
skipBytes(offset[i] - currentFilePosition);
try {
sasFileStream.readFully(temp, 0, length[i]);
} catch (EOFException e) {
Expand Down
77 changes: 77 additions & 0 deletions src/test/java/com/epam/parso/BugsTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,11 @@
import com.epam.parso.impl.SasFileReaderImpl;
import org.junit.Test;

import java.io.ByteArrayInputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;
Expand Down Expand Up @@ -139,4 +143,77 @@ public void testCompressionMethodsIssue55() throws Exception {
assertThat(sasFileReader.getSasFileProperties().getCompressionMethod()).isNull();
}
}

@Test(timeout = 1000)
public void testInfinityLoopOnEmptyStreamIssue56() {
ByteArrayInputStream emptyStream = new ByteArrayInputStream(new byte[]{});
SasFileReaderImpl sasFileReader = new SasFileReaderImpl(emptyStream);
assertThat(sasFileReader.getSasFileProperties().getRowCount()).isEqualTo(0);
}

@Test(timeout = 1000)
public void testInfinityLoopOnIncompleteStreamIssue56() {
ByteArrayInputStream emptyStream = new ByteArrayInputStream(new byte[]{1, 2, 3, 4, 5, 6, 7, 8, 9});
SasFileReaderImpl sasFileReader = new SasFileReaderImpl(emptyStream);
assertThat(sasFileReader.getSasFileProperties().getRowCount()).isEqualTo(0);
}

/**
* This has invalid page and header lengths:
* - page length = 31612 (7C 7B 00 00)
* - header length = 32126 (7E 7D 00 00)
* See this row in a hex editor:
* 000000C0: 00 00 00 00 7E 7D 00 00 │ 7C 7B 00 00 B8 00 00 00
* <p>
* File size is 17408 - it is smaller than specified lengths, so both lengths refer
* to the out of file bounds offsets.
*/
private static final String INVALID_FILE_NAME = "invalid_lengths.sas7bdat";

@Test(timeout = 1000)
public void testBrokenFileOnFileChannelIssue58() throws Exception {
// These skips were performed performed for the FileChannel by the parser before the fix:
// [32, 2, 1, 32, 21, 16, 8, 17120, 0, 0, 0, ... infinity loop of zeros]
try (InputStream is = Files.newInputStream(
Paths.get(this.getClass().getResource("/bugs/" + INVALID_FILE_NAME).toURI()))) {
SasFileReader sasFileReader = new SasFileReaderImpl(is);
assertThat(sasFileReader.getSasFileProperties().getRowCount()).isEqualTo(0);
}
}

@Test(timeout = 1000)
public void testBrokenFileOnBufferedFileInputStreamIssue58() throws Exception {
// These skips were performed performed for the buffered stream by the parser before the fix:
// [32, 2, 1, 32, 21, 16, 8, 7936, 23902]
try (InputStream is = this.getClass().getResourceAsStream("/bugs/" + INVALID_FILE_NAME)) {
SasFileReader sasFileReader = new SasFileReaderImpl(is);
assertThat(sasFileReader.getSasFileProperties().getRowCount()).isEqualTo(0);
}
}

@Test(timeout = 1000)
public void testBrokenFileOnUnbufferedFileInputStreamIssue58() throws Exception {
// These skips were performed for the buffered stream by the parser before the fix:
// [32, 2, 1, 32, 21, 16, 8, 31838]
try (InputStream is = new FileInputStream("target/test-classes/bugs/" + INVALID_FILE_NAME)) {
SasFileReader sasFileReader = new SasFileReaderImpl(is);
assertThat(sasFileReader.getSasFileProperties().getRowCount()).isEqualTo(0);
}
}

@Test(timeout = 1000)
public void testInfinityLoopBufferedIssue58() throws Exception {
try (InputStream is = this.getClass().getResourceAsStream("/bugs/sas_infinite_loop.sas7bdat")) {
SasFileReader sasFileReader = new SasFileReaderImpl(is);
assertThat(sasFileReader.getSasFileProperties().getRowCount()).isEqualTo(0);
}
}

@Test(timeout = 1000)
public void testInfinityLoopUnbufferedIssue58() throws Exception {
try (InputStream is = new FileInputStream("target/test-classes/bugs/sas_infinite_loop.sas7bdat")) {
SasFileReader sasFileReader = new SasFileReaderImpl(is);
assertThat(sasFileReader.getSasFileProperties().getRowCount()).isEqualTo(0);
}
}
}
Binary file not shown.
Binary file not shown.