Skip to content

Commit 55347ea

Browse files
justinhorvitzcopybara-github
authored andcommitted
Fix calculations locating the explicit bit in the bit-packed AttributeContainer$Large.
If the number of attributes is a multiple of 8, the explicit bit for the last attribute is leaking into the array element for the first attribute's value and clobbering it. PiperOrigin-RevId: 510179709 Change-Id: Ifa04204fd645d3e8817eaf600de42a46b8434d28
1 parent 004c73c commit 55347ea

File tree

2 files changed

+39
-17
lines changed

2 files changed

+39
-17
lines changed

src/main/java/com/google/devtools/build/lib/packages/AttributeContainer.java

Lines changed: 22 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -321,25 +321,32 @@ static final class Large extends Frozen {
321321
// - stateIndex: an index into the state[] array.
322322
// - valueIndex: an index into the attributeValues array.
323323

324+
/** Calculates the number of bytes necessary to have an explicit bit for each attribute. */
324325
private static int prefixSize(int attrCount) {
325326
// ceil(max attributes / 8)
326-
return (attrCount + 7) >> 3;
327+
return (attrCount + 7) / 8;
327328
}
328329

329-
/** Set the specified bit in the byte array. Assumes bitIndex is a valid index. */
330-
private static void setBit(byte[] bits, int bitIndex) {
331-
int idx = (bitIndex + 1);
332-
int explicitByte = bits[idx >> 3];
333-
byte mask = (byte) (1 << (idx & 0x07));
334-
bits[idx >> 3] = (byte) (explicitByte | mask);
330+
/**
331+
* Sets the explicit bit for {@code attrIndex} in the byte array. Assumes {@code attrIndex} is a
332+
* valid index.
333+
*/
334+
private static void setExplicitBit(byte[] bytes, int attrIndex) {
335+
int byteIndex = attrIndex / 8;
336+
int bitIndex = attrIndex % 8;
337+
byte byteValue = bytes[byteIndex];
338+
bytes[byteIndex] = (byte) (byteValue | (1 << bitIndex));
335339
}
336340

337-
/** Get the specified bit in the byte array. Assumes bitIndex is a valid index. */
338-
private static boolean getBit(byte[] bits, int bitIndex) {
339-
int idx = (bitIndex + 1);
340-
int explicitByte = bits[idx >> 3];
341-
int mask = (byte) (1 << (idx & 0x07));
342-
return (explicitByte & mask) != 0;
341+
/**
342+
* Gets the explicit bit for {@code attrIndex} in the byte array. Assumes {@code attrIndex} is a
343+
* valid index.
344+
*/
345+
private static boolean getExplicitBit(byte[] bytes, int attrIndex) {
346+
int byteIndex = attrIndex / 8;
347+
int bitIndex = attrIndex % 8;
348+
byte byteValue = bytes[byteIndex];
349+
return (byteValue & (1 << bitIndex)) != 0;
343350
}
344351

345352
/**
@@ -367,7 +374,7 @@ private Large(Object[] attrValues, BitSet explicitAttrs) {
367374
continue;
368375
}
369376
if (explicitAttrs.get(attrIndex)) {
370-
setBit(state, attrIndex);
377+
setExplicitBit(state, attrIndex);
371378
}
372379
state[index + p] = (byte) attrIndex;
373380
values[index] = attrValue;
@@ -381,7 +388,7 @@ private Large(Object[] attrValues, BitSet explicitAttrs) {
381388
*/
382389
@Override
383390
boolean isAttributeValueExplicitlySpecified(int attrIndex) {
384-
return (attrIndex >= 0) && getBit(state, attrIndex);
391+
return (attrIndex >= 0) && getExplicitBit(state, attrIndex);
385392
}
386393

387394
@Nullable

src/test/java/com/google/devtools/build/lib/packages/AttributeContainerTest.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -196,8 +196,8 @@ public void testMutableGetRawAttributeValuesReturnsNullSafeCopy() {
196196
@Test
197197
public void testGetRawAttributeValuesReturnsCopy() {
198198
AttributeContainer mutable = new Mutable(2);
199-
mutable.setAttributeValue(0, "hi", /*explicit=*/ true);
200-
mutable.setAttributeValue(1, null, /*explicit=*/ false);
199+
mutable.setAttributeValue(0, "hi", /* explicit= */ true);
200+
mutable.setAttributeValue(1, null, /* explicit= */ false);
201201

202202
AttributeContainer container = mutable.freeze();
203203
// Nulls don't make it into the frozen representation.
@@ -206,4 +206,19 @@ public void testGetRawAttributeValuesReturnsCopy() {
206206
container.getRawAttributeValues().set(0, "foo");
207207
assertThat(container.getRawAttributeValues()).containsExactly("hi");
208208
}
209+
210+
/** Regression test for b/269593252. */
211+
@Test
212+
public void boundaryOfLargeContainer() {
213+
AttributeContainer mutable = new Mutable(128);
214+
mutable.setAttributeValue(0, "0", /* explicit= */ true);
215+
mutable.setAttributeValue(127, "127", /* explicit= */ true);
216+
217+
AttributeContainer frozen = mutable.freeze();
218+
219+
assertThat(frozen.getAttributeValue(0)).isEqualTo("0");
220+
assertThat(frozen.isAttributeValueExplicitlySpecified(0)).isTrue();
221+
assertThat(frozen.getAttributeValue(127)).isEqualTo("127");
222+
assertThat(frozen.isAttributeValueExplicitlySpecified(127)).isTrue();
223+
}
209224
}

0 commit comments

Comments
 (0)