Skip to content

Commit bc24390

Browse files
yimingz-atensorflow-copybara
authored andcommitted
Fix zlib.
PiperOrigin-RevId: 367282082
1 parent 880ce64 commit bc24390

File tree

4 files changed

+102
-3
lines changed

4 files changed

+102
-3
lines changed

tensorflow_serving/util/net_http/compression/BUILD

+2
Original file line numberDiff line numberDiff line change
@@ -35,5 +35,7 @@ cc_test(
3535
deps = [
3636
":gzip_zlib",
3737
"//tensorflow_serving/core/test_util:test_main",
38+
"@com_google_absl//absl/strings",
39+
"@com_google_googletest//:gtest",
3840
],
3941
)

tensorflow_serving/util/net_http/compression/gzip_zlib.cc

+4-2
Original file line numberDiff line numberDiff line change
@@ -695,7 +695,9 @@ int ZLib::UncompressAtMost(Bytef *dest, uLongf *destLen, const Bytef *source,
695695
// mode, we also check the gzip footer to make sure we pass the gzip
696696
// consistency checks. We RETURN true iff both types of checks pass.
697697
bool ZLib::UncompressChunkDone() {
698-
assert(!first_chunk_ && uncomp_init_);
698+
if (first_chunk_ || !uncomp_init_) {
699+
return false;
700+
}
699701
// Make sure we're at the end-of-compressed-data point. This means
700702
// if we call inflate with Z_FINISH we won't consume any input or
701703
// write any output
@@ -771,7 +773,7 @@ int ZLib::Uncompress(Bytef *dest, uLongf *destLen, const Bytef *source,
771773

772774
// read uncompress length from gzip footer
773775
uLongf ZLib::GzipUncompressedLength(const Bytef *source, uLong len) {
774-
assert(len > 4);
776+
if (len <= 4) return 0; // malformed data.
775777
return (static_cast<uLongf>(source[len - 1]) << 24) +
776778
(static_cast<uLongf>(source[len - 2]) << 16) +
777779
(static_cast<uLongf>(source[len - 3]) << 8) +

tensorflow_serving/util/net_http/compression/gzip_zlib.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,8 @@ class ZLib {
173173
int Uncompress(Bytef *dest, uLongf *destLen, const Bytef *source,
174174
uLong sourceLen);
175175

176-
// Get the uncompressed size from the gzip footer.
176+
// Get the uncompressed size from the gzip footer. Returns 0 if source is too
177+
// short (len < 5).
177178
uLongf GzipUncompressedLength(const Bytef *source, uLong len);
178179

179180
// Special helper function to help uncompress gzipped documents:

tensorflow_serving/util/net_http/compression/gzip_zlib_test.cc

+94
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ limitations under the License.
2020
#include <string>
2121
#include <vector>
2222

23+
#include <gmock/gmock.h>
2324
#include <gtest/gtest.h>
25+
#include "absl/strings/str_cat.h"
2426
#include "absl/strings/string_view.h"
2527

2628
namespace tensorflow {
@@ -602,6 +604,98 @@ TEST(ZLibTest, BytewiseRead) {
602604
ASSERT_EQ(truncated_output, text);
603605
}
604606

607+
TEST(ZLibTest, TruncatedData) {
608+
const int kBufferLen = 64;
609+
std::string uncompressed = "Hello, World!";
610+
std::string compressed(
611+
"\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\xf3\x48\xcd\xc9\xc9"
612+
"\xd7\x51\x08\xcf\x2f\xca\x49\x51\x04\x00\xd0\xc3\x4a\xec\x0d"
613+
"\x00\x00\x00",
614+
33);
615+
616+
// Verify that "compressed" contains valid gzip data.
617+
{
618+
ZLib zlib;
619+
// zlib.SetGzipHeaderMode();
620+
char uncompbuf[kBufferLen];
621+
bzero(uncompbuf, kBufferLen);
622+
uLongf uncomplen = kBufferLen;
623+
int err = zlib.Uncompress(
624+
reinterpret_cast<Bytef*>(uncompbuf), &uncomplen,
625+
reinterpret_cast<const Bytef*>(compressed.c_str()), compressed.size());
626+
ASSERT_EQ(err, Z_OK);
627+
ASSERT_EQ(uncompressed, absl::string_view(uncompbuf, uncomplen));
628+
}
629+
630+
// Test truncated data with ZLib::Uncompress().
631+
for (int len = compressed.size() - 1; len > 0; len--) {
632+
SCOPED_TRACE(absl::StrCat("Decompressing first ", len, " out of ",
633+
compressed.size(), " bytes"));
634+
ZLib zlib;
635+
// zlib.SetGzipHeaderMode();
636+
char uncompbuf[kBufferLen];
637+
bzero(uncompbuf, kBufferLen);
638+
uLongf uncomplen = kBufferLen;
639+
int err = zlib.Uncompress(
640+
reinterpret_cast<Bytef*>(uncompbuf), &uncomplen,
641+
reinterpret_cast<const Bytef*>(compressed.c_str()), len);
642+
ASSERT_NE(err, Z_OK);
643+
}
644+
645+
// Test truncated data with ZLib::UncompressAtMost() and
646+
// ZLib::UncompressDone().
647+
for (int len = compressed.size() - 1; len > 0; len--) {
648+
SCOPED_TRACE(absl::StrCat("Decompressing first ", len, " out of ",
649+
compressed.size(), " bytes"));
650+
ZLib zlib;
651+
// zlib.SetGzipHeaderMode();
652+
char uncompbuf[kBufferLen];
653+
bzero(uncompbuf, kBufferLen);
654+
uLongf uncomplen = kBufferLen;
655+
uLongf complen = len;
656+
int err = zlib.UncompressAtMost(
657+
reinterpret_cast<Bytef*>(uncompbuf), &uncomplen,
658+
reinterpret_cast<const Bytef*>(compressed.c_str()), &complen);
659+
ASSERT_EQ(err, Z_OK);
660+
ASSERT_EQ(complen, 0);
661+
if (uncomplen > 0) {
662+
EXPECT_THAT(
663+
uncompressed,
664+
testing::StartsWith(std::string(uncompbuf).substr(0, uncomplen)));
665+
}
666+
ASSERT_FALSE(zlib.UncompressChunkDone());
667+
}
668+
}
669+
670+
TEST(ZLibTest, GzipUncompressedLength) {
671+
ZLib zlib;
672+
673+
// "Hello, World!", compressed.
674+
std::string hello_world(
675+
"\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\xf3\x48\xcd\xc9\xc9"
676+
"\xd7\x51\x08\xcf\x2f\xca\x49\x51\x04\x00\xd0\xc3\x4a\xec\x0d"
677+
"\x00\x00\x00",
678+
33);
679+
EXPECT_EQ(13, zlib.GzipUncompressedLength(
680+
reinterpret_cast<const Bytef*>(hello_world.c_str()),
681+
hello_world.size()));
682+
683+
// Empty string, "", compressed.
684+
std::string empty(
685+
"\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\x03\x03\x00\x00\x00\x00"
686+
"\x00\x00\x00\x00\x00",
687+
20);
688+
EXPECT_EQ(0,
689+
zlib.GzipUncompressedLength(
690+
reinterpret_cast<const Bytef*>(empty.c_str()), empty.size()));
691+
692+
std::string bad_data("\x01\x01\x01\x01", 4);
693+
for (int len = 0; len <= bad_data.size(); len++) {
694+
EXPECT_EQ(0, zlib.GzipUncompressedLength(
695+
reinterpret_cast<const Bytef*>(bad_data.c_str()), len));
696+
}
697+
}
698+
605699
} // namespace
606700
} // namespace net_http
607701
} // namespace serving

0 commit comments

Comments
 (0)