Skip to content

Commit 2216a0d

Browse files
authored
Update (#706)
Update * add ASAN/MSAN unaligned read specializations * add "brotli" prefix to u_uint64 type * increment version to 1.0.06 * fix CoverityScan "unused assignment" warning * fix JDK 8<->9 incompatibility * add encoder optimization for empty input * regenerate JS decoder * unbreak Travis builds
1 parent d4cd6cd commit 2216a0d

File tree

14 files changed

+195
-98
lines changed

14 files changed

+195
-98
lines changed

.travis.yml

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,10 @@ matrix:
115115
## We'll just test 4.4 and the most recent version.
116116
###
117117
- os: osx
118-
env: BUILD_SYSTEM=cmake C_COMPILER=gcc-6 CXX_COMPILER=g++-6
118+
env: BUILD_SYSTEM=cmake C_COMPILER=gcc CXX_COMPILER=g++
119119
- os: osx
120120
env: BUILD_SYSTEM=cmake C_COMPILER=gcc-4.9 CXX_COMPILER=g++-4.9
121121
- os: osx
122-
osx_image: xcode9.3
123122
env: BUILD_SYSTEM=cmake
124123

125124
###
@@ -166,6 +165,7 @@ matrix:
166165
- os: linux
167166
sudo: required
168167
language: java
168+
jdk: oraclejdk9
169169
env: BUILD_SYSTEM=bazel
170170
addons:
171171
apt:
@@ -174,11 +174,13 @@ matrix:
174174
key_url: "https://storage.googleapis.com/bazel-apt/doc/apt-key.pub.gpg"
175175
- ubuntu-toolchain-r-test
176176
packages:
177-
- oracle-java8-installer
178177
- bazel
179178

180179
- os: osx
181180
env: BUILD_SYSTEM=bazel
181+
# Latest image with Java 1.8 (required to install Bazel).
182+
osx_image: xcode9.3
183+
language: java
182184

183185
before_install:
184186
###

c/common/platform.h

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,33 @@ static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
298298
}
299299
#else /* BROTLI_ALIGNED_READ */
300300
/* Unaligned memory access is allowed: just cast pointer to requested type. */
301+
#if defined(ADDRESS_SANITIZER) || defined(THREAD_SANITIZER) || \
302+
defined(MEMORY_SANITIZER)
303+
/* Consider we have an unaligned load/store of 4 bytes from address 0x...05.
304+
AddressSanitizer will treat it as a 3-byte access to the range 05:07 and
305+
will miss a bug if 08 is the first unaddressable byte.
306+
ThreadSanitizer will also treat this as a 3-byte access to 05:07 and will
307+
miss a race between this access and some other accesses to 08.
308+
MemorySanitizer will correctly propagate the shadow on unaligned stores
309+
and correctly report bugs on unaligned loads, but it may not properly
310+
update and report the origin of the uninitialized memory.
311+
For all three tools, replacing an unaligned access with a tool-specific
312+
callback solves the problem. */
313+
#if defined(__cplusplus)
314+
extern "C" {
315+
#endif /* __cplusplus */
316+
uint16_t __sanitizer_unaligned_load16(const void* p);
317+
uint32_t __sanitizer_unaligned_load32(const void* p);
318+
uint64_t __sanitizer_unaligned_load64(const void* p);
319+
void __sanitizer_unaligned_store64(void* p, uint64_t v);
320+
#if defined(__cplusplus)
321+
} /* extern "C" */
322+
#endif /* __cplusplus */
323+
#define BrotliUnalignedRead16 __sanitizer_unaligned_load16
324+
#define BrotliUnalignedRead32 __sanitizer_unaligned_load32
325+
#define BrotliUnalignedRead64 __sanitizer_unaligned_load64
326+
#define BrotliUnalignedWrite64 __sanitizer_unaligned_store64
327+
#else
301328
static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) {
302329
return *(const uint16_t*)p;
303330
}
@@ -316,14 +343,14 @@ static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
316343
/* If __attribute__(aligned) is available, use that. Otherwise, memcpy. */
317344

318345
#if BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0)
319-
typedef __attribute__((aligned(1))) uint64_t unaligned_uint64_t;
346+
typedef __attribute__((aligned(1))) uint64_t brotli_unaligned_uint64_t;
320347

321348
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
322-
return (uint64_t) ((unaligned_uint64_t*) p)[0];
349+
return (uint64_t) ((brotli_unaligned_uint64_t*) p)[0];
323350
}
324351
static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
325-
unaligned_uint64_t* dwords = (unaligned_uint64_t*) p;
326-
dwords[0] = (unaligned_uint64_t) v;
352+
brotli_unaligned_uint64_t* dwords = (brotli_unaligned_uint64_t*) p;
353+
dwords[0] = (brotli_unaligned_uint64_t) v;
327354
}
328355
#else /* BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) */
329356
static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) {
@@ -337,6 +364,7 @@ static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) {
337364
}
338365
#endif /* BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) */
339366
#endif /* BROTLI_64_BITS */
367+
#endif /* ASAN / TSAN / MSAN */
340368
#endif /* BROTLI_ALIGNED_READ */
341369

342370
#if BROTLI_LITTLE_ENDIAN

c/common/version.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@
1414
BrotliEncoderVersion methods. */
1515

1616
/* Semantic version, calculated as (MAJOR << 24) | (MINOR << 12) | PATCH */
17-
#define BROTLI_VERSION 0x1000005
17+
#define BROTLI_VERSION 0x1000006
1818

1919
/* This macro is used by build system to produce Libtool-friendly soname. See
2020
https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html
2121
*/
2222

2323
/* ABI version, calculated as (CURRENT << 24) | (REVISION << 12) | AGE */
24-
#define BROTLI_ABI_VERSION 0x1005000
24+
#define BROTLI_ABI_VERSION 0x1006000
2525

2626
#endif /* BROTLI_COMMON_VERSION_H_ */

c/enc/metablock.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -181,7 +181,8 @@ void BrotliBuildMetaBlock(MemoryManager* m,
181181
ComputeDistanceCost(cmds, num_commands,
182182
&orig_params.dist, &orig_params.dist, &dist_cost);
183183
if (dist_cost < best_dist_cost) {
184-
best_dist_cost = dist_cost;
184+
/* NB: currently unused; uncomment when more param tuning is added. */
185+
/* best_dist_cost = dist_cost; */
185186
params->dist = orig_params.dist;
186187
}
187188
}

java/org/brotli/dec/DictionaryData.java

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
package org.brotli.dec;
88

9-
import java.io.UnsupportedEncodingException;
109
import java.nio.ByteBuffer;
1110

1211
/**
@@ -22,14 +21,7 @@ final class DictionaryData {
2221
private static void unpackDictionaryData(
2322
ByteBuffer dictionary, String data0, String data1, String skipFlip) {
2423
// Initialize lower 7 bits of every byte in the dictionary.
25-
byte[] dict;
26-
try {
27-
// NB: String#getBytes(String) is present in JDK 1.1, while other variants require JDK 1.6 and
28-
// above.
29-
dict = (data0 + data1).getBytes("US-ASCII");
30-
} catch (UnsupportedEncodingException e) {
31-
throw new RuntimeException(e); // cannot happen
32-
}
24+
byte[] dict = Utils.toUsAsciiBytes(data0 + data1);
3325
if (dict.length != dictionary.capacity()) {
3426
throw new RuntimeException("Corrupted brotli dictionary");
3527
}
@@ -53,7 +45,7 @@ private static void unpackDictionaryData(
5345
static {
5446
ByteBuffer dictionary = ByteBuffer.allocateDirect(122784);
5547
unpackDictionaryData(dictionary, DATA0, DATA1, SKIP_FLIP);
56-
dictionary.flip();
48+
Utils.flipBuffer(dictionary);
5749
Dictionary.setData(dictionary.asReadOnlyBuffer());
5850
}
5951
}

java/org/brotli/dec/Utils.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88

99
import java.io.IOException;
1010
import java.io.InputStream;
11+
import java.io.UnsupportedEncodingException;
12+
import java.nio.Buffer;
1113

1214
/**
1315
* A set of utility methods.
@@ -71,4 +73,19 @@ static int readInput(InputStream src, byte[] dst, int offset, int length) {
7173
static void closeInput(InputStream src) throws IOException {
7274
src.close();
7375
}
76+
77+
static byte[] toUsAsciiBytes(String src) {
78+
try {
79+
// NB: String#getBytes(String) is present in JDK 1.1, while other variants require JDK 1.6 and
80+
// above.
81+
return src.getBytes("US-ASCII");
82+
} catch (UnsupportedEncodingException e) {
83+
throw new RuntimeException(e); // cannot happen
84+
}
85+
}
86+
87+
// Crazy pills factory: code compiled for JDK8 does not work on JRE9.
88+
static void flipBuffer(Buffer buffer) {
89+
buffer.flip();
90+
}
7491
}

java/org/brotli/wrapper/dec/Decoder.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
package org.brotli.wrapper.dec;
88

99
import java.io.IOException;
10+
import java.nio.Buffer;
1011
import java.nio.ByteBuffer;
1112
import java.nio.channels.ReadableByteChannel;
1213
import java.util.ArrayList;
@@ -83,7 +84,7 @@ int decode() throws IOException {
8384
break;
8485
}
8586
ByteBuffer inputBuffer = decoder.getInputBuffer();
86-
inputBuffer.clear();
87+
((Buffer) inputBuffer).clear();
8788
int bytesRead = source.read(inputBuffer);
8889
if (bytesRead == -1) {
8990
fail("unexpected end of input");
@@ -107,7 +108,7 @@ int decode() throws IOException {
107108
}
108109

109110
void discard(int length) {
110-
buffer.position(buffer.position() + length);
111+
((Buffer) buffer).position(buffer.position() + length);
111112
if (!buffer.hasRemaining()) {
112113
buffer = null;
113114
}
@@ -116,7 +117,7 @@ void discard(int length) {
116117
int consume(ByteBuffer dst) {
117118
ByteBuffer slice = buffer.slice();
118119
int limit = Math.min(slice.remaining(), dst.remaining());
119-
slice.limit(limit);
120+
((Buffer) slice).limit(limit);
120121
dst.put(slice);
121122
discard(limit);
122123
return limit;

java/org/brotli/wrapper/enc/BrotliEncoderChannel.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
package org.brotli.wrapper.enc;
88

99
import java.io.IOException;
10+
import java.nio.Buffer;
1011
import java.nio.ByteBuffer;
1112
import java.nio.channels.ClosedChannelException;
1213
import java.nio.channels.WritableByteChannel;
@@ -65,10 +66,10 @@ public int write(ByteBuffer src) throws IOException {
6566
while (src.hasRemaining() && encode(EncoderJNI.Operation.PROCESS)) {
6667
int limit = Math.min(src.remaining(), inputBuffer.remaining());
6768
ByteBuffer slice = src.slice();
68-
slice.limit(limit);
69+
((Buffer) slice).limit(limit);
6970
inputBuffer.put(slice);
7071
result += limit;
71-
src.position(src.position() + limit);
72+
((Buffer) src).position(src.position() + limit);
7273
}
7374
return result;
7475
}

java/org/brotli/wrapper/enc/BrotliEncoderChannelTest.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.io.FileInputStream;
1111
import java.io.IOException;
1212
import java.io.InputStream;
13+
import java.nio.Buffer;
1314
import java.nio.ByteBuffer;
1415
import java.nio.channels.Channels;
1516
import java.nio.channels.WritableByteChannel;
@@ -95,8 +96,8 @@ private static void run(String entryName, TestMode mode) throws Throwable {
9596
while (src.hasRemaining()) {
9697
int limit = Math.min(CHUNK_SIZE, src.remaining());
9798
ByteBuffer slice = src.slice();
98-
slice.limit(limit);
99-
src.position(src.position() + limit);
99+
((Buffer) slice).limit(limit);
100+
((Buffer) src).position(src.position() + limit);
100101
encoder.write(slice);
101102
}
102103
break;
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/* Copyright 2018 Google Inc. All Rights Reserved.
2+
3+
Distributed under MIT license.
4+
See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
5+
*/
6+
7+
package org.brotli.wrapper.enc;
8+
9+
import static org.junit.Assert.assertEquals;
10+
11+
import org.brotli.integration.BrotliJniTestBase;
12+
import org.brotli.wrapper.dec.Decoder;
13+
import java.io.IOException;
14+
import org.junit.Test;
15+
import org.junit.runner.RunWith;
16+
import org.junit.runners.JUnit4;
17+
18+
/** Tests for {@link org.brotli.wrapper.enc.Encoder}. */
19+
@RunWith(JUnit4.class)
20+
public class EmptyInputTest extends BrotliJniTestBase {
21+
@Test
22+
public void testEmptyInput() throws IOException {
23+
byte[] data = new byte[0];
24+
byte[] encoded = Encoder.compress(data);
25+
assertEquals(1, encoded.length);
26+
byte[] decoded = Decoder.decompress(encoded);
27+
assertEquals(0, decoded.length);
28+
}
29+
}

0 commit comments

Comments
 (0)