From 3bad87738f130cb216f5b01fab5dfdc60be52880 Mon Sep 17 00:00:00 2001 From: Markus Schorn Date: Thu, 21 Jun 2007 12:44:40 +0000 Subject: [PATCH] Fix for 193505, Unprotected read-operations can corrupt the index. --- .../cdt/internal/core/pdom/db/Chunk.java | 110 +++++++++++------- .../cdt/internal/core/pdom/db/Database.java | 26 +++-- .../cdt/internal/ui/indexview/IndexView.java | 21 +++- 3 files changed, 104 insertions(+), 53 deletions(-) diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Chunk.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Chunk.java index ef28bed112c..def665109b6 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Chunk.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Chunk.java @@ -21,7 +21,7 @@ import org.eclipse.core.runtime.CoreException; * Caches the content of a piece of the database. */ final class Chunk { - final private ByteBuffer fBuffer; + final private byte[] fBuffer= new byte[Database.CHUNK_SIZE]; final Database fDatabase; final int fSequenceNumber; @@ -33,14 +33,13 @@ final class Chunk { Chunk(Database db, int sequenceNumber) { fDatabase= db; - fBuffer= ByteBuffer.allocate(Database.CHUNK_SIZE); fSequenceNumber= sequenceNumber; } void read() throws CoreException { try { - fBuffer.position(0); - fDatabase.getChannel().read(fBuffer, fSequenceNumber*Database.CHUNK_SIZE); + final ByteBuffer buf= ByteBuffer.wrap(fBuffer); + fDatabase.getChannel().read(buf, fSequenceNumber*Database.CHUNK_SIZE); } catch (IOException e) { throw new CoreException(new DBStatus(e)); } @@ -48,87 +47,120 @@ final class Chunk { void flush() throws CoreException { try { - fBuffer.position(0); - fDatabase.getChannel().write(fBuffer, fSequenceNumber*Database.CHUNK_SIZE); + final ByteBuffer buf= ByteBuffer.wrap(fBuffer); + fDatabase.getChannel().write(buf, fSequenceNumber*Database.CHUNK_SIZE); } catch (IOException e) { throw new CoreException(new DBStatus(e)); } fDirty= false; } - public void putByte(int offset, byte value) { + public void putByte(final int offset, final byte value) { assert fLocked; fDirty= true; - fBuffer.put(offset % Database.CHUNK_SIZE, value); + fBuffer[offset % Database.CHUNK_SIZE]= value; } - public byte getByte(int offset) { - return fBuffer.get(offset % Database.CHUNK_SIZE); + public byte getByte(final int offset) { + return fBuffer[offset % Database.CHUNK_SIZE]; } - public byte[] getBytes(int offset, int length) { - byte[] bytes = new byte[length]; - fBuffer.position(offset % Database.CHUNK_SIZE); - fBuffer.get(bytes, 0, length); + public byte[] getBytes(final int offset, final int length) { + final byte[] bytes = new byte[length]; + System.arraycopy(fBuffer, offset % Database.CHUNK_SIZE, bytes, 0, length); return bytes; } - public void putBytes(int offset, byte[] bytes) { + public void putBytes(final int offset, final byte[] bytes) { assert fLocked; fDirty= true; - fBuffer.position(offset % Database.CHUNK_SIZE); - fBuffer.put(bytes, 0, bytes.length); + System.arraycopy(bytes, 0, fBuffer, offset % Database.CHUNK_SIZE, bytes.length); } - public void putInt(int offset, int value) { + public void putInt(final int offset, final int value) { assert fLocked; fDirty= true; - fBuffer.putInt(offset % Database.CHUNK_SIZE, value); + int idx= offset % Database.CHUNK_SIZE; + fBuffer[idx]= (byte)(value >> 24); + fBuffer[++idx]= (byte)(value >> 16); + fBuffer[++idx]= (byte)(value >> 8); + fBuffer[++idx]= (byte)(value); } - public int getInt(int offset) { - return fBuffer.getInt(offset % Database.CHUNK_SIZE); + public int getInt(final int offset) { + int idx= offset % Database.CHUNK_SIZE; + return ((fBuffer[idx] & 0xff) << 24) | + ((fBuffer[++idx] & 0xff) << 16) | + ((fBuffer[++idx] & 0xff) << 8) | + ((fBuffer[++idx] & 0xff) << 0); } - public void putShort(int offset, short value) { + public void putShort(final int offset, final short value) { assert fLocked; fDirty= true; - fBuffer.putShort(offset % Database.CHUNK_SIZE, value); + int idx= offset % Database.CHUNK_SIZE; + fBuffer[idx]= (byte)(value >> 8); + fBuffer[++idx]= (byte)(value); } - public short getShort(int offset) { - return fBuffer.getShort(offset % Database.CHUNK_SIZE); + public short getShort(final int offset) { + int idx= offset % Database.CHUNK_SIZE; + return (short) (((fBuffer[idx] << 8) | (fBuffer[++idx] & 0xff))); } - public long getLong(int offset) { - return fBuffer.getLong(offset % Database.CHUNK_SIZE); + public long getLong(final int offset) { + int idx= offset % Database.CHUNK_SIZE; + return ((((long)fBuffer[idx] & 0xff) << 56) | + (((long)fBuffer[++idx] & 0xff) << 48) | + (((long)fBuffer[++idx] & 0xff) << 40) | + (((long)fBuffer[++idx] & 0xff) << 32) | + (((long)fBuffer[++idx] & 0xff) << 24) | + (((long)fBuffer[++idx] & 0xff) << 16) | + (((long)fBuffer[++idx] & 0xff) << 8) | + (((long)fBuffer[++idx] & 0xff) << 0)); } - public void putLong(int offset, long value) { + public void putLong(final int offset, final long value) { assert fLocked; fDirty= true; - fBuffer.putLong(offset % Database.CHUNK_SIZE, value); + int idx= offset % Database.CHUNK_SIZE; + + fBuffer[idx]= (byte)(value >> 56); + fBuffer[++idx]= (byte)(value >> 48); + fBuffer[++idx]= (byte)(value >> 40); + fBuffer[++idx]= (byte)(value >> 32); + fBuffer[++idx]= (byte)(value >> 24); + fBuffer[++idx]= (byte)(value >> 16); + fBuffer[++idx]= (byte)(value >> 8); + fBuffer[++idx]= (byte)(value); } - public void putChar(int offset, char value) { + public void putChar(final int offset, final char value) { assert fLocked; fDirty= true; - fBuffer.putChar(offset % Database.CHUNK_SIZE, value); + int idx= offset % Database.CHUNK_SIZE; + fBuffer[idx]= (byte)(value >> 8); + fBuffer[++idx]= (byte)(value); } - public char getChar(int offset) { - return fBuffer.getChar(offset % Database.CHUNK_SIZE); + public char getChar(final int offset) { + int idx= offset % Database.CHUNK_SIZE; + return (char) (((fBuffer[idx] << 8) | (fBuffer[++idx] & 0xff))); } - public void getCharArray(int offset, char[] result) { - fBuffer.position(offset % Database.CHUNK_SIZE); - fBuffer.asCharBuffer().get(result); + public void getCharArray(final int offset, final char[] result) { + final ByteBuffer buf= ByteBuffer.wrap(fBuffer); + buf.position(offset % Database.CHUNK_SIZE); + buf.asCharBuffer().get(result); } - void clear(int offset, int length) { + void clear(final int offset, final int length) { assert fLocked; fDirty= true; - fBuffer.position(offset % Database.CHUNK_SIZE); - fBuffer.put(new byte[length]); + int idx= (offset % Database.CHUNK_SIZE); + final int end= idx + length; + for (; idx < end; idx++) { + fBuffer[idx]= 0; + } } } diff --git a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Database.java b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Database.java index 859332df2e3..5a11f93cc27 100644 --- a/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Database.java +++ b/core/org.eclipse.cdt.core/parser/org/eclipse/cdt/internal/core/pdom/db/Database.java @@ -138,6 +138,8 @@ public class Database { Chunk header= getChunk(0); header.clear(0, CHUNK_SIZE); setVersion(version); + + // chunks have been removed from the cache, so we are fine here. chunks = new Chunk[] {header}; try { getChannel().truncate(CHUNK_SIZE); @@ -252,16 +254,20 @@ public class Database { } private int createNewChunk() throws CoreException { - Chunk[] oldtoc = chunks; - int n = oldtoc.length; - int offset = n * CHUNK_SIZE; - chunks = new Chunk[n + 1]; - System.arraycopy(oldtoc, 0, chunks, 0, n); - final Chunk chunk= new Chunk(this, n); + // prepare new chunk array + final int oldLen= chunks.length; + final Chunk chunk= new Chunk(this, oldLen); chunk.fDirty= true; - chunks[n]= chunk; - fCache.add(chunk, true); - return offset; + + Chunk[] newchunks = new Chunk[oldLen+1]; + // the content of the chunk array may be modified by the cache, so sync it. + synchronized (fCache) { + System.arraycopy(chunks, 0, newchunks, 0, oldLen); + newchunks[oldLen]= chunk; + chunks= newchunks; + fCache.add(chunk, true); + } + return oldLen * CHUNK_SIZE; } private int getFirstBlock(int blocksize) throws CoreException { @@ -408,6 +414,8 @@ public class Database { public void close() throws CoreException { setReadOnly(true); removeChunksFromCache(); + + // chunks have been removed from the cache, so we are fine chunks= new Chunk[0]; try { file.close(); diff --git a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/indexview/IndexView.java b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/indexview/IndexView.java index cdd3fd3b417..02ee5484a3b 100644 --- a/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/indexview/IndexView.java +++ b/core/org.eclipse.cdt.ui/src/org/eclipse/cdt/internal/ui/indexview/IndexView.java @@ -77,6 +77,7 @@ public class IndexView extends ViewPart implements PDOM.IListener, IElementChang private IndexAction findReferencesAction; Filter filter = new Filter(); public boolean isLinking = false; + private volatile boolean fUpdateRequested= false; public void toggleExternalDefs() { if (!filter.showExternalDefs) { @@ -406,13 +407,23 @@ public class IndexView extends ViewPart implements PDOM.IListener, IElementChang } public void handleChange(PDOM pdom) { - viewer.getControl().getDisplay().asyncExec(new Runnable() { - public void run() { - viewer.refresh(); - } - }); + requestUpdate(); } + private void requestUpdate() { + if (!fUpdateRequested) { + fUpdateRequested= true; + viewer.getControl().getDisplay().asyncExec(new Runnable() { + public void run() { + fUpdateRequested= false; + if (!viewer.getControl().isDisposed()) { + viewer.refresh(); + } + } + }); + } + } + public void elementChanged(ElementChangedEvent event) { // Only respond to post change events if (event.getType() != ElementChangedEvent.POST_CHANGE)