mirror of
https://github.com/shadowsocks/shadowsocks-libev.git
synced 2026-10-28 10:44:43 +08:00
* Make headers and leaf modules compile as C++
Wrap the declarations of every project header in extern "C" (after the
system includes, which must keep C++ linkage), so converted modules and
the remaining C files agree on linkage.
In the leaf modules, cast allocator and memchr results explicitly,
rename identifiers called new, replace the getpwnam_r VLA with the
fixed 16 KiB buffer the loop already capped itself at, and make the
rlimit initialiser conversion explicit. All of this is still valid C.
* Compile the leaf modules as C++
Rename base64, json, ipset, process, ppbloom, rule, ssurl and cache from
.c to .cpp without touching their contents, and update the CMake source
lists, debian/copyright and the docs.
Ported code keeps -Wall; -Wextra is now opt-in through
ss_strict_warnings() for code written as C++ (the core tests).
check_no_heap.py gains a ratchet baseline for the converted modules,
which still allocate the way the C code did. A new check_cxx_runtime
test verifies with nm that the programs and libshadowsocks-c.a still
need no C++ runtime library, so C consumers are unaffected.
* Fix the Windows branches of process.cpp for C++
Cast allocator results and the thread argument explicitly and
value-initialise JOBOBJECT_EXTENDED_LIMIT_INFORMATION with {}. Found by
the zig x86_64-windows-gnu cross build.
* Keep clang-tidy clean for the converted modules
Once the C headers are included from C++ translation units,
bugprone-dynamic-static-initializers reports each extern variable
declaration in them; none is defined in a header, so disable the check.
Mark the two bounded memchr searches in ssurl.cpp, which
bugprone-not-null-terminated-result misreads as string copies.
* check_cxx_runtime: ignore glibc symbol versions
nm on glibc prints __cxa_atexit@GLIBC_2.2.5, which the allowlist for the
libc-provided __cxa_atexit/__cxa_finalize did not match.
* Keep GCC's C++-only warnings off for modules converted from C
GCC's C++ -Wall includes -Wsign-compare and -Wclass-memaccess, which C's
-Wall does not, so the converted modules failed -Werror on GCC (Linux,
UCRT64) although nothing in them changed. They keep the warning set they
were written against; code under ss_strict_warnings() re-enables both.
100 lines
2.6 KiB
C++
100 lines
2.6 KiB
C++
/* SPDX-License-Identifier: GPL-3.0-or-later */
|
|
#include "ipset.h"
|
|
#include <assert.h>
|
|
#include <stdlib.h>
|
|
#include "utils.h"
|
|
|
|
/* NULL is an empty subtree. A full node represents every address below it.
|
|
* Recursion is bounded by the address width, never by the number of rules. */
|
|
struct ss_ipset_node {
|
|
struct ss_ipset_node *child[2];
|
|
bool full;
|
|
};
|
|
|
|
static struct ss_ipset_node *
|
|
node_new(bool full)
|
|
{
|
|
struct ss_ipset_node *node = (struct ss_ipset_node *)ss_malloc(sizeof(*node));
|
|
node->child[0] = node->child[1] = NULL;
|
|
node->full = full;
|
|
return node;
|
|
}
|
|
|
|
static void
|
|
node_free(struct ss_ipset_node *node)
|
|
{
|
|
if (node != NULL) {
|
|
node_free(node->child[0]);
|
|
node_free(node->child[1]);
|
|
free(node);
|
|
}
|
|
}
|
|
|
|
void
|
|
ss_ipset_clear(struct ss_ipset *set)
|
|
{
|
|
node_free(set->root);
|
|
set->root = NULL;
|
|
}
|
|
|
|
static struct ss_ipset_node *
|
|
node_assign(struct ss_ipset_node *node, const uint8_t *address,
|
|
unsigned bit, unsigned prefix, bool present)
|
|
{
|
|
if ((node == NULL && !present) || (node != NULL && node->full && present)) {
|
|
return node;
|
|
}
|
|
if (bit == prefix) {
|
|
node_free(node);
|
|
return present ? node_new(true) : NULL;
|
|
}
|
|
if (node == NULL) {
|
|
node = node_new(false);
|
|
} else if (node->full) {
|
|
node->child[0] = node_new(true);
|
|
node->child[1] = node_new(true);
|
|
node->full = false;
|
|
}
|
|
unsigned side = (address[bit / 8] >> (7 - bit % 8)) & 1;
|
|
node->child[side] = node_assign(node->child[side], address, bit + 1, prefix, present);
|
|
if (node->child[0] == NULL && node->child[1] == NULL) {
|
|
free(node);
|
|
return NULL;
|
|
}
|
|
if (node->child[0] != NULL && node->child[0]->full &&
|
|
node->child[1] != NULL && node->child[1]->full) {
|
|
node_free(node->child[0]);
|
|
node_free(node->child[1]);
|
|
node->child[0] = node->child[1] = NULL;
|
|
node->full = true;
|
|
}
|
|
return node;
|
|
}
|
|
|
|
void
|
|
ss_ipset_assign(struct ss_ipset *set, const uint8_t *address,
|
|
unsigned width, unsigned prefix, bool present)
|
|
{
|
|
assert(width == 32 || width == 128);
|
|
if (prefix <= width) {
|
|
set->root = node_assign(set->root, address, 0, prefix, present);
|
|
}
|
|
}
|
|
|
|
bool
|
|
ss_ipset_contains(const struct ss_ipset *set, const uint8_t *address, unsigned width)
|
|
{
|
|
const struct ss_ipset_node *node = set->root;
|
|
for (unsigned bit = 0; node != NULL; bit++) {
|
|
if (node->full) {
|
|
return true;
|
|
}
|
|
if (bit == width) {
|
|
break;
|
|
}
|
|
unsigned side = (address[bit / 8] >> (7 - bit % 8)) & 1;
|
|
node = node->child[side];
|
|
}
|
|
return false;
|
|
}
|