mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-30 23:53:32 +01:00
Merge branch '25162_zstd_static'
This commit is contained in:
commit
a1dd8afc16
6
changes/ticket25162
Normal file
6
changes/ticket25162
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
o Minor features (compression, zstd):
|
||||||
|
- When running with zstd, Tor now considers using advanced functions that
|
||||||
|
the zstd maintainers have labeled as potentially unstable. To
|
||||||
|
prevent breakage, Tor will only use this functionality when
|
||||||
|
the runtime version of the zstd library matches the version
|
||||||
|
with which it were compiled. Closes ticket 25162.
|
@ -61,6 +61,8 @@ AC_ARG_ENABLE(cargo-online-mode,
|
|||||||
AS_HELP_STRING(--enable-cargo-online-mode, [Allow cargo to make network requests to fetch crates. For builds with rust only.]))
|
AS_HELP_STRING(--enable-cargo-online-mode, [Allow cargo to make network requests to fetch crates. For builds with rust only.]))
|
||||||
AC_ARG_ENABLE(restart-debugging,
|
AC_ARG_ENABLE(restart-debugging,
|
||||||
AS_HELP_STRING(--enable-restart-debugging, [Build Tor with support for debugging in-process restart. Developers only.]))
|
AS_HELP_STRING(--enable-restart-debugging, [Build Tor with support for debugging in-process restart. Developers only.]))
|
||||||
|
AC_ARG_ENABLE(zstd-advanced-apis,
|
||||||
|
AS_HELP_STRING(--disable-zstd-advanced-apis, [Build without support for zstd's "static-only" APIs.]))
|
||||||
|
|
||||||
if test "x$enable_coverage" != "xyes" -a "x$enable_asserts_in_tests" = "xno" ; then
|
if test "x$enable_coverage" != "xyes" -a "x$enable_asserts_in_tests" = "xno" ; then
|
||||||
AC_MSG_ERROR([Can't disable assertions outside of coverage build])
|
AC_MSG_ERROR([Can't disable assertions outside of coverage build])
|
||||||
@ -114,6 +116,10 @@ if test "$enable_restart_debugging" = "yes"; then
|
|||||||
[Defined if we're building with support for in-process restart debugging.])
|
[Defined if we're building with support for in-process restart debugging.])
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "$enable_zstd_advanced_apis" != "no"; then
|
||||||
|
AC_DEFINE(ENABLE_ZSTD_ADVANCED_APIS, 1,
|
||||||
|
[Defined if we're going to try to use zstd's "static-only" APIs.])
|
||||||
|
fi
|
||||||
|
|
||||||
# systemd support
|
# systemd support
|
||||||
if test "x$enable_systemd" = "xno"; then
|
if test "x$enable_systemd" = "xno"; then
|
||||||
|
@ -663,3 +663,13 @@ tor_compress_init(void)
|
|||||||
tor_zstd_init();
|
tor_zstd_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Warn if we had any problems while setting up our compression libraries.
|
||||||
|
*
|
||||||
|
* (This isn't part of tor_compress_init, since the logs aren't set up yet.)
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
tor_compress_log_init_warnings(void)
|
||||||
|
{
|
||||||
|
tor_zstd_warn_if_version_mismatched();
|
||||||
|
}
|
||||||
|
|
||||||
|
@ -87,6 +87,7 @@ void tor_compress_free_(tor_compress_state_t *state);
|
|||||||
size_t tor_compress_state_size(const tor_compress_state_t *state);
|
size_t tor_compress_state_size(const tor_compress_state_t *state);
|
||||||
|
|
||||||
void tor_compress_init(void);
|
void tor_compress_init(void);
|
||||||
|
void tor_compress_log_init_warnings(void);
|
||||||
|
|
||||||
#endif /* !defined(TOR_COMPRESS_H) */
|
#endif /* !defined(TOR_COMPRESS_H) */
|
||||||
|
|
||||||
|
@ -18,6 +18,13 @@
|
|||||||
#include "compress.h"
|
#include "compress.h"
|
||||||
#include "compress_zstd.h"
|
#include "compress_zstd.h"
|
||||||
|
|
||||||
|
#ifdef ENABLE_ZSTD_ADVANCED_APIS
|
||||||
|
/* This is a lie, but we make sure it doesn't get us in trouble by wrapping
|
||||||
|
* all invocations of zstd's static-only functions in a check to make sure
|
||||||
|
* that the compile-time version matches the run-time version. */
|
||||||
|
#define ZSTD_STATIC_LINKING_ONLY
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_ZSTD
|
#ifdef HAVE_ZSTD
|
||||||
#include <zstd.h>
|
#include <zstd.h>
|
||||||
#endif
|
#endif
|
||||||
@ -51,21 +58,29 @@ tor_zstd_method_supported(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Format a zstd version number as a string in <b>buf</b>. */
|
||||||
|
static void
|
||||||
|
tor_zstd_format_version(char *buf, size_t buflen, unsigned version_number)
|
||||||
|
{
|
||||||
|
tor_snprintf(buf, buflen,
|
||||||
|
"%u.%u.%u",
|
||||||
|
version_number / 10000 % 100,
|
||||||
|
version_number / 100 % 100,
|
||||||
|
version_number % 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define VERSION_STR_MAX_LEN 16 /* more than enough space for 99.99.99 */
|
||||||
|
|
||||||
/** Return a string representation of the version of the currently running
|
/** Return a string representation of the version of the currently running
|
||||||
* version of libzstd. Returns NULL if Zstandard is unsupported. */
|
* version of libzstd. Returns NULL if Zstandard is unsupported. */
|
||||||
const char *
|
const char *
|
||||||
tor_zstd_get_version_str(void)
|
tor_zstd_get_version_str(void)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_ZSTD
|
#ifdef HAVE_ZSTD
|
||||||
static char version_str[16];
|
static char version_str[VERSION_STR_MAX_LEN];
|
||||||
size_t version_number;
|
|
||||||
|
|
||||||
version_number = ZSTD_versionNumber();
|
tor_zstd_format_version(version_str, sizeof(version_str),
|
||||||
tor_snprintf(version_str, sizeof(version_str),
|
ZSTD_versionNumber());
|
||||||
"%d.%d.%d",
|
|
||||||
(int) version_number / 10000 % 100,
|
|
||||||
(int) version_number / 100 % 100,
|
|
||||||
(int) version_number % 100);
|
|
||||||
|
|
||||||
return version_str;
|
return version_str;
|
||||||
#else /* !(defined(HAVE_ZSTD)) */
|
#else /* !(defined(HAVE_ZSTD)) */
|
||||||
@ -85,6 +100,26 @@ tor_zstd_get_header_version_str(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef TOR_UNIT_TESTS
|
||||||
|
static int static_apis_disable_for_testing = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/** Return true iff we can use the "static-only" APIs. */
|
||||||
|
int
|
||||||
|
tor_zstd_can_use_static_apis(void)
|
||||||
|
{
|
||||||
|
#if defined(ZSTD_STATIC_LINKING_ONLY) && defined(HAVE_ZSTD)
|
||||||
|
#ifdef TOR_UNIT_TESTS
|
||||||
|
if (static_apis_disable_for_testing) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return (ZSTD_VERSION_NUMBER == ZSTD_versionNumber());
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
/** Internal Zstandard state for incremental compression/decompression.
|
/** Internal Zstandard state for incremental compression/decompression.
|
||||||
* The body of this struct is not exposed. */
|
* The body of this struct is not exposed. */
|
||||||
struct tor_zstd_compress_state_t {
|
struct tor_zstd_compress_state_t {
|
||||||
@ -112,9 +147,11 @@ struct tor_zstd_compress_state_t {
|
|||||||
|
|
||||||
#ifdef HAVE_ZSTD
|
#ifdef HAVE_ZSTD
|
||||||
/** Return an approximate number of bytes stored in memory to hold the
|
/** Return an approximate number of bytes stored in memory to hold the
|
||||||
* Zstandard compression/decompression state. */
|
* Zstandard compression/decompression state. This is a fake estimate
|
||||||
|
* based on inspecting the zstd source: tor_zstd_state_size_precalc() is
|
||||||
|
* more accurate when it's allowed to use "static-only" functions */
|
||||||
static size_t
|
static size_t
|
||||||
tor_zstd_state_size_precalc(int compress, int preset)
|
tor_zstd_state_size_precalc_fake(int compress, int preset)
|
||||||
{
|
{
|
||||||
tor_assert(preset > 0);
|
tor_assert(preset > 0);
|
||||||
|
|
||||||
@ -171,6 +208,24 @@ tor_zstd_state_size_precalc(int compress, int preset)
|
|||||||
|
|
||||||
return memory_usage;
|
return memory_usage;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Return an approximate number of bytes stored in memory to hold the
|
||||||
|
* Zstandard compression/decompression state. */
|
||||||
|
static size_t
|
||||||
|
tor_zstd_state_size_precalc(int compress, int preset)
|
||||||
|
{
|
||||||
|
#ifdef ZSTD_STATIC_LINKING_ONLY
|
||||||
|
if (tor_zstd_can_use_static_apis()) {
|
||||||
|
if (compress) {
|
||||||
|
return ZSTD_estimateCStreamSize(preset);
|
||||||
|
} else {
|
||||||
|
/* Could use DStream, but that takes a windowSize. */
|
||||||
|
return ZSTD_estimateDCtxSize();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return tor_zstd_state_size_precalc_fake(compress, preset);
|
||||||
|
}
|
||||||
#endif /* defined(HAVE_ZSTD) */
|
#endif /* defined(HAVE_ZSTD) */
|
||||||
|
|
||||||
/** Construct and return a tor_zstd_compress_state_t object using
|
/** Construct and return a tor_zstd_compress_state_t object using
|
||||||
@ -440,3 +495,34 @@ tor_zstd_init(void)
|
|||||||
atomic_counter_init(&total_zstd_allocation);
|
atomic_counter_init(&total_zstd_allocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Warn if the header and library versions don't match. */
|
||||||
|
void
|
||||||
|
tor_zstd_warn_if_version_mismatched(void)
|
||||||
|
{
|
||||||
|
#if defined(HAVE_ZSTD) && defined(ENABLE_ZSTD_ADVANCED_APIS)
|
||||||
|
if (! tor_zstd_can_use_static_apis()) {
|
||||||
|
char header_version[VERSION_STR_MAX_LEN];
|
||||||
|
char runtime_version[VERSION_STR_MAX_LEN];
|
||||||
|
tor_zstd_format_version(header_version, sizeof(header_version),
|
||||||
|
ZSTD_VERSION_NUMBER);
|
||||||
|
tor_zstd_format_version(runtime_version, sizeof(runtime_version),
|
||||||
|
ZSTD_versionNumber());
|
||||||
|
|
||||||
|
log_warn(LD_GENERAL,
|
||||||
|
"Tor was compiled with zstd %s, but is running with zstd %s. "
|
||||||
|
"For safety, we'll avoid using advanced zstd functionality.",
|
||||||
|
header_version, runtime_version);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef TOR_UNIT_TESTS
|
||||||
|
/** Testing only: disable usage of static-only APIs, so we can make sure that
|
||||||
|
* we still work without them. */
|
||||||
|
void
|
||||||
|
tor_zstd_set_static_apis_disabled_for_testing(int disabled)
|
||||||
|
{
|
||||||
|
static_apis_disable_for_testing = disabled;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
@ -17,6 +17,8 @@ const char *tor_zstd_get_version_str(void);
|
|||||||
|
|
||||||
const char *tor_zstd_get_header_version_str(void);
|
const char *tor_zstd_get_header_version_str(void);
|
||||||
|
|
||||||
|
int tor_zstd_can_use_static_apis(void);
|
||||||
|
|
||||||
/** Internal state for an incremental Zstandard compression/decompression. */
|
/** Internal state for an incremental Zstandard compression/decompression. */
|
||||||
typedef struct tor_zstd_compress_state_t tor_zstd_compress_state_t;
|
typedef struct tor_zstd_compress_state_t tor_zstd_compress_state_t;
|
||||||
|
|
||||||
@ -41,6 +43,11 @@ size_t tor_zstd_compress_state_size(const tor_zstd_compress_state_t *state);
|
|||||||
size_t tor_zstd_get_total_allocation(void);
|
size_t tor_zstd_get_total_allocation(void);
|
||||||
|
|
||||||
void tor_zstd_init(void);
|
void tor_zstd_init(void);
|
||||||
|
void tor_zstd_warn_if_version_mismatched(void);
|
||||||
|
|
||||||
|
#ifdef TOR_UNIT_TESTS
|
||||||
|
void tor_zstd_set_static_apis_disabled_for_testing(int disabled);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* !defined(TOR_COMPRESS_ZSTD_H) */
|
#endif /* !defined(TOR_COMPRESS_ZSTD_H) */
|
||||||
|
|
||||||
|
@ -3332,6 +3332,8 @@ tor_init(int argc, char *argv[])
|
|||||||
if (strstr(version, "alpha") || strstr(version, "beta"))
|
if (strstr(version, "alpha") || strstr(version, "beta"))
|
||||||
log_notice(LD_GENERAL, "This version is not a stable Tor release. "
|
log_notice(LD_GENERAL, "This version is not a stable Tor release. "
|
||||||
"Expect more bugs than usual.");
|
"Expect more bugs than usual.");
|
||||||
|
|
||||||
|
tor_compress_log_init_warnings();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_RUST
|
#ifdef HAVE_RUST
|
||||||
|
@ -16,6 +16,7 @@
|
|||||||
#include "memarea.h"
|
#include "memarea.h"
|
||||||
#include "util_process.h"
|
#include "util_process.h"
|
||||||
#include "log_test_helpers.h"
|
#include "log_test_helpers.h"
|
||||||
|
#include "compress_zstd.h"
|
||||||
|
|
||||||
#ifdef HAVE_PWD_H
|
#ifdef HAVE_PWD_H
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
@ -2396,6 +2397,37 @@ test_util_compress_stream_impl(compress_method_t method,
|
|||||||
tor_free(buf3);
|
tor_free(buf3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Setup function for compression tests: handles x-zstd:nostatic
|
||||||
|
*/
|
||||||
|
static void *
|
||||||
|
compression_test_setup(const struct testcase_t *testcase)
|
||||||
|
{
|
||||||
|
tor_assert(testcase->setup_data);
|
||||||
|
tor_assert(testcase->setup_data != (void*)TT_SKIP);
|
||||||
|
const char *methodname = testcase->setup_data;
|
||||||
|
|
||||||
|
if (!strcmp(methodname, "x-zstd:nostatic")) {
|
||||||
|
methodname = "x-zstd";
|
||||||
|
tor_zstd_set_static_apis_disabled_for_testing(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (void *)methodname;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Cleanup for compression tests: disables nostatic */
|
||||||
|
static int
|
||||||
|
compression_test_cleanup(const struct testcase_t *testcase, void *ptr)
|
||||||
|
{
|
||||||
|
(void)testcase;
|
||||||
|
(void)ptr;
|
||||||
|
tor_zstd_set_static_apis_disabled_for_testing(0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct testcase_setup_t compress_setup = {
|
||||||
|
compression_test_setup, compression_test_cleanup
|
||||||
|
};
|
||||||
|
|
||||||
/** Run unit tests for compression functions */
|
/** Run unit tests for compression functions */
|
||||||
static void
|
static void
|
||||||
test_util_compress(void *arg)
|
test_util_compress(void *arg)
|
||||||
@ -6095,22 +6127,22 @@ test_util_get_unquoted_path(void *arg)
|
|||||||
{ #name, test_util_ ## name, flags, NULL, NULL }
|
{ #name, test_util_ ## name, flags, NULL, NULL }
|
||||||
|
|
||||||
#define COMPRESS(name, identifier) \
|
#define COMPRESS(name, identifier) \
|
||||||
{ "compress/" #name, test_util_compress, 0, &passthrough_setup, \
|
{ "compress/" #name, test_util_compress, 0, &compress_setup, \
|
||||||
(char*)(identifier) }
|
(char*)(identifier) }
|
||||||
|
|
||||||
#define COMPRESS_CONCAT(name, identifier) \
|
#define COMPRESS_CONCAT(name, identifier) \
|
||||||
{ "compress_concat/" #name, test_util_decompress_concatenated, 0, \
|
{ "compress_concat/" #name, test_util_decompress_concatenated, 0, \
|
||||||
&passthrough_setup, \
|
&compress_setup, \
|
||||||
(char*)(identifier) }
|
(char*)(identifier) }
|
||||||
|
|
||||||
#define COMPRESS_JUNK(name, identifier) \
|
#define COMPRESS_JUNK(name, identifier) \
|
||||||
{ "compress_junk/" #name, test_util_decompress_junk, 0, \
|
{ "compress_junk/" #name, test_util_decompress_junk, 0, \
|
||||||
&passthrough_setup, \
|
&compress_setup, \
|
||||||
(char*)(identifier) }
|
(char*)(identifier) }
|
||||||
|
|
||||||
#define COMPRESS_DOS(name, identifier) \
|
#define COMPRESS_DOS(name, identifier) \
|
||||||
{ "compress_dos/" #name, test_util_decompress_dos, 0, \
|
{ "compress_dos/" #name, test_util_decompress_dos, 0, \
|
||||||
&passthrough_setup, \
|
&compress_setup, \
|
||||||
(char*)(identifier) }
|
(char*)(identifier) }
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
@ -6141,11 +6173,13 @@ struct testcase_t util_tests[] = {
|
|||||||
COMPRESS(gzip, "gzip"),
|
COMPRESS(gzip, "gzip"),
|
||||||
COMPRESS(lzma, "x-tor-lzma"),
|
COMPRESS(lzma, "x-tor-lzma"),
|
||||||
COMPRESS(zstd, "x-zstd"),
|
COMPRESS(zstd, "x-zstd"),
|
||||||
|
COMPRESS(zstd_nostatic, "x-zstd:nostatic"),
|
||||||
COMPRESS(none, "identity"),
|
COMPRESS(none, "identity"),
|
||||||
COMPRESS_CONCAT(zlib, "deflate"),
|
COMPRESS_CONCAT(zlib, "deflate"),
|
||||||
COMPRESS_CONCAT(gzip, "gzip"),
|
COMPRESS_CONCAT(gzip, "gzip"),
|
||||||
COMPRESS_CONCAT(lzma, "x-tor-lzma"),
|
COMPRESS_CONCAT(lzma, "x-tor-lzma"),
|
||||||
COMPRESS_CONCAT(zstd, "x-zstd"),
|
COMPRESS_CONCAT(zstd, "x-zstd"),
|
||||||
|
COMPRESS_CONCAT(zstd_nostatic, "x-zstd:nostatic"),
|
||||||
COMPRESS_CONCAT(none, "identity"),
|
COMPRESS_CONCAT(none, "identity"),
|
||||||
COMPRESS_JUNK(zlib, "deflate"),
|
COMPRESS_JUNK(zlib, "deflate"),
|
||||||
COMPRESS_JUNK(gzip, "gzip"),
|
COMPRESS_JUNK(gzip, "gzip"),
|
||||||
@ -6154,6 +6188,7 @@ struct testcase_t util_tests[] = {
|
|||||||
COMPRESS_DOS(gzip, "gzip"),
|
COMPRESS_DOS(gzip, "gzip"),
|
||||||
COMPRESS_DOS(lzma, "x-tor-lzma"),
|
COMPRESS_DOS(lzma, "x-tor-lzma"),
|
||||||
COMPRESS_DOS(zstd, "x-zstd"),
|
COMPRESS_DOS(zstd, "x-zstd"),
|
||||||
|
COMPRESS_DOS(zstd_nostatic, "x-zstd:nostatic"),
|
||||||
UTIL_TEST(gzip_compression_bomb, TT_FORK),
|
UTIL_TEST(gzip_compression_bomb, TT_FORK),
|
||||||
UTIL_LEGACY(datadir),
|
UTIL_LEGACY(datadir),
|
||||||
UTIL_LEGACY(memarea),
|
UTIL_LEGACY(memarea),
|
||||||
|
Loading…
Reference in New Issue
Block a user