Merge commit '227425b90e9a671118026689dd30967e127a1090' as 'external/toxcore/c-toxcore'

This commit is contained in:
2023-07-25 11:53:09 +02:00
467 changed files with 116591 additions and 0 deletions

View File

@ -0,0 +1,8 @@
################################################
# autotools-linux
FROM toxchat/nacl:latest
# Copy the sources and run the build.
COPY --chown=builder:builder . /home/builder/c-toxcore/
WORKDIR /home/builder/c-toxcore
RUN CC=gcc .github/scripts/autotools-linux

View File

@ -0,0 +1,3 @@
#!/bin/sh
docker build -t toxchat/c-toxcore:autotools -f other/docker/autotools/Dockerfile .

View File

@ -0,0 +1,6 @@
FROM toxchat/haskell:hs-cimple AS cimple
FROM ubuntu:20.04
COPY --from=cimple /bin/cimplefmt /bin/
WORKDIR /work
ENTRYPOINT ["/bin/cimplefmt"]

View File

@ -0,0 +1,8 @@
#!/bin/sh
if [ "$1" = "-u" ]; then
shift
docker pull toxchat/haskell:hs-cimple
docker build -t toxchat/cimplefmt -f other/docker/cimplefmt/Dockerfile .
fi
docker run --rm -v "$PWD:/work" toxchat/cimplefmt "$@"

View File

@ -0,0 +1,30 @@
################################################
# cmake-asan
FROM ubuntu:20.04
RUN apt-get update && \
DEBIAN_FRONTEND="noninteractive" apt-get install -y --no-install-recommends \
clang \
cmake \
libconfig-dev \
libgtest-dev \
libopus-dev \
libsodium-dev \
libvpx-dev \
llvm-dev \
ninja-build \
pkg-config \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
COPY entrypoint.sh /
RUN ["chmod", "755", "/entrypoint.sh"]
WORKDIR /home/builder
RUN groupadd -r -g 1000 builder \
&& useradd --no-log-init -r -g builder -u 1000 builder \
&& chown builder:builder /home/builder
USER builder
ENV CC=clang CXX=clang++
ENTRYPOINT ["/entrypoint.sh"]

View File

@ -0,0 +1,9 @@
#!/bin/sh
set -eu
SANITIZER="${1:-asan}"
cp -a /c-toxcore .
cd c-toxcore
.circleci/cmake-"$SANITIZER"

View File

@ -0,0 +1,6 @@
#!/bin/sh
SANITIZER="${1:-asan}"
docker build -t toxchat/c-toxcore:circleci other/docker/circleci
docker run --rm -it -v "$PWD:/c-toxcore" toxchat/c-toxcore:circleci "$SANITIZER"

View File

@ -0,0 +1,78 @@
FROM toxchat/c-toxcore:sources AS src
FROM ubuntu:20.04 AS build
RUN apt-get update && \
DEBIAN_FRONTEND="noninteractive" apt-get install -y --no-install-recommends \
clang \
cmake \
gcc \
git \
golang \
libconfig-dev \
libgtest-dev \
libopus-dev \
libsodium-dev \
libvpx-dev \
llvm-dev \
make \
ninja-build \
pkg-config \
python3-pip \
python3-pygments \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/* \
&& pip3 install --no-cache-dir gcovr
ENV CC=clang \
CXX=clang++ \
PYTHONUNBUFFERED=1
SHELL ["/bin/bash", "-c"]
WORKDIR /work
COPY --from=src /src/ /work/
RUN source .github/scripts/flags-coverage.sh \
&& go get github.com/things-go/go-socks5 \
&& go build other/proxy/proxy_server.go \
&& cmake -B_build -H. -GNinja \
-DCMAKE_C_FLAGS="$C_FLAGS" \
-DCMAKE_CXX_FLAGS="$CXX_FLAGS" \
-DCMAKE_EXE_LINKER_FLAGS="$LD_FLAGS" \
-DCMAKE_UNITY_BUILD=ON \
-DENABLE_SHARED=OFF \
-DMIN_LOGGER_LEVEL=TRACE \
-DMUST_BUILD_TOXAV=ON \
-DNON_HERMETIC_TESTS=ON \
-DSTRICT_ABI=ON \
-DAUTOTEST=ON \
-DPROXY_TEST=ON \
-DUSE_IPV6=OFF \
&& cmake --build _build --parallel 8 --target install
WORKDIR /work/_build
RUN /work/proxy_server \
& ctest -j50 --output-on-failure --rerun-failed --repeat until-pass:6
WORKDIR /work/mallocfail
RUN ["git", "clone", "--depth=1", "https://github.com/ralight/mallocfail", "/work/mallocfail"]
COPY run_mallocfail /usr/local/bin/
COPY syscall_funcs.c src/
RUN gcc -fPIC -shared -O2 -g3 -Wall -Ideps/uthash -Ideps/sha3 deps/*/*.c src/*.c -o mallocfail.so -ldl -lbacktrace \
&& install mallocfail.so /usr/local/lib/mallocfail.so
WORKDIR /work/_build
RUN ["run_mallocfail", "--ctest=2", "--jobs=8"]
RUN ["gcovr", \
"--sort-percentage", \
"--gcov-executable=llvm-cov gcov", \
"--html-details=html/", \
"--root=..", \
"--exclude=CMakeFiles/", \
"--exclude=_deps/", \
"--exclude=(.+/)?auto_tests/", \
"--exclude=.+_test.cc?$", \
"--exclude=(.+/)?other/", \
"--exclude=(.+/)?testing/"]
FROM nginx:alpine
COPY --from=build /work/_build/html/coverage_details.html /usr/share/nginx/html/index.html
COPY --from=build /work/_build/html/ /usr/share/nginx/html/

View File

@ -0,0 +1,3 @@
// Dummy, actual one is here: https://github.com/ralight/mallocfail/blob/master/src/mallocfail.h
int should_malloc_fail(void);

View File

@ -0,0 +1,7 @@
#!/bin/sh
set -eux
docker build -t toxchat/c-toxcore:sources -f other/docker/sources/Dockerfile .
docker build -t toxchat/c-toxcore:coverage other/docker/coverage
docker run --rm -it -p "28192:80" toxchat/c-toxcore:coverage

View File

@ -0,0 +1,166 @@
#!/usr/bin/env python3
"""Run a test repeatedly with mallocfail.
Usage: run_mallocfail [--ctest=<cost>] [<exe>...]
This runs the programs with mallocfail until there are no more additional
stack hashes for mallocfail to try out.
Passing "--ctest" additionally runs all the tests with a cost lower than the
given flag value. Cost is measured in seconds of runtime.
You need to build mallocfail (https://github.com/ralight/mallocfail) and install
it to /usr/local/lib/mallocfail. Change _MALLOCFAIL_SO below if you want it
elsewhere.
"""
import glob
import multiprocessing
import os
import shutil
import subprocess
import sys
import tempfile
import time
from typing import Dict
from typing import List
from typing import NoReturn
from typing import Optional
from typing import Tuple
_PRIMER = "./unit_util_test"
_MALLOCFAIL_SO = "/usr/local/lib/mallocfail.so"
_HASHES = "mallocfail_hashes"
_HASHES_PREV = "mallocfail_hashes.prev"
_TIMEOUT = 3.0
_ENV = {
"LD_PRELOAD": _MALLOCFAIL_SO,
"UBSAN_OPTIONS": "color=always,print_stacktrace=1,exitcode=11",
}
def run_mallocfail(tmpdir: str, timeout: float, exe: str,
iteration: int) -> bool:
"""Run a program with mallocfail."""
print(f"\x1b[1;33mmallocfail '{exe}' run #{iteration}\x1b[0m")
hashes = os.path.join(tmpdir, _HASHES)
hashes_prev = os.path.join(tmpdir, _HASHES_PREV)
if os.path.exists(hashes):
shutil.copy(hashes, hashes_prev)
try:
proc = subprocess.run([exe], timeout=timeout, env=_ENV, cwd=tmpdir)
except subprocess.TimeoutExpired:
print(f"\x1b[1;34mProgram {exe} timed out\x1b[0m")
return True
finally:
assert os.path.exists(hashes)
if os.path.exists(hashes_prev):
with open(hashes_prev, "r") as prev:
with open(hashes, "r") as cur:
if prev.read() == cur.read():
# Done: no new stack hashes.
return False
if proc.returncode in (0, 1):
# Process exited cleanly (success or failure).
pass
elif proc.returncode == -6:
# Assertion failed.
pass
elif proc.returncode == -14:
print(f"\x1b[0;34mProgram '{exe}' timed out\x1b[0m")
else:
print(
f"\x1b[1;32mProgram '{exe}' failed to handle OOM situation cleanly\x1b[0m"
)
raise Exception("Aborting test")
return True
def ctest_costs() -> Dict[str, float]:
with open("Testing/Temporary/CTestCostData.txt", "r") as fh:
costs = {}
for line in fh.readlines():
if line.startswith("---"):
break
prog, _, cost = line.rstrip().split(" ")
costs[prog] = float(cost)
return costs
def find_prog(name: str) -> Tuple[Optional[str], ...]:
def attempt(path: str) -> Optional[str]:
if os.path.exists(path):
return path
return None
return (attempt(f"./unit_{name}_test"), attempt(f"./auto_{name}_test"))
def parse_flags(args: List[str]) -> Tuple[Dict[str, str], List[str]]:
flags: Dict[str, str] = {}
exes: List[str] = []
for arg in args:
if arg.startswith("--"):
flag, value = arg.split("=", 1)
flags[flag] = value
else:
exes.append(arg)
return flags, exes
def loop_mallocfail(tmpdir: str, timeout: float, exe: str) -> None:
i = 1
while run_mallocfail(tmpdir, timeout, exe, i):
i += 1
def isolated_mallocfail(timeout: int, exe: str) -> None:
with tempfile.TemporaryDirectory(prefix="mallocfail") as tmpdir:
print(f"\x1b[1;33mRunning for {exe} in isolated path {tmpdir}\x1b[0m")
shutil.copy(exe, os.path.join(tmpdir, exe))
shutil.copy(_HASHES, os.path.join(tmpdir, _HASHES))
loop_mallocfail(tmpdir, timeout, exe)
def main(args: List[str]) -> None:
"""Run a program repeatedly under mallocfail."""
if len(args) == 1:
print(f"Usage: {args[0]} <exe>")
sys.exit(1)
flags, exes = parse_flags(args[1:])
timeout = _TIMEOUT
if "--ctest" in flags:
costs = ctest_costs()
max_cost = float(flags["--ctest"])
timeout = max(max_cost + 1, timeout)
exes.extend(prog for test in costs.keys() for prog in find_prog(test)
if costs[test] <= max_cost and prog)
if "--jobs" in flags:
jobs = int(flags["--jobs"])
else:
jobs = 1
# Start by running util_test, which allocates no memory of its own, just
# to prime the mallocfail hashes so it doesn't make global initialisers
# such as llvm_gcov_init fail.
if os.path.exists(_PRIMER):
print(f"\x1b[1;33mPriming hashes with unit_util_test\x1b[0m")
loop_mallocfail(".", timeout, _PRIMER)
print(f"\x1b[1;33m--------------------------------\x1b[0m")
print(f"\x1b[1;33mStarting mallocfail for {len(exes)} programs:\x1b[0m")
print(f"\x1b[1;33m{exes}\x1b[0m")
print(f"\x1b[1;33m--------------------------------\x1b[0m")
time.sleep(1)
with multiprocessing.Pool(jobs) as p:
done = tuple(
p.starmap(isolated_mallocfail, ((timeout, exe) for exe in exes)))
print(f"\x1b[1;32mCompleted {len(done)} programs\x1b[0m")
if __name__ == "__main__":
main(sys.argv)

View File

@ -0,0 +1,149 @@
#define _GNU_SOURCE
#include "mallocfail.h"
#include <dlfcn.h>
#include <errno.h>
#include <stdlib.h>
#include <stdarg.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <sys/types.h>
static int (*libc_ioctl)(int fd, unsigned long request, ...);
static int (*libc_bind)(int sockfd, const struct sockaddr *addr,
socklen_t addrlen);
static int (*libc_getsockopt)(int sockfd, int level, int optname,
void *optval, socklen_t *optlen);
static int (*libc_setsockopt)(int sockfd, int level, int optname,
const void *optval, socklen_t optlen);
static ssize_t (*libc_recv)(int sockfd, void *buf, size_t len, int flags);
static ssize_t (*libc_recvfrom)(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen);
static ssize_t (*libc_send)(int sockfd, const void *buf, size_t len, int flags);
static ssize_t(*libc_sendto)(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen);
static int (*libc_socket)(int domain, int type, int protocol);
static int (*libc_listen)(int sockfd, int backlog);
__attribute__((__constructor__))
static void init(void)
{
libc_ioctl = dlsym(RTLD_NEXT, "ioctl");
libc_bind = dlsym(RTLD_NEXT, "bind");
libc_getsockopt = dlsym(RTLD_NEXT, "getsockopt");
libc_setsockopt = dlsym(RTLD_NEXT, "setsockopt");
libc_recv = dlsym(RTLD_NEXT, "recv");
libc_recvfrom = dlsym(RTLD_NEXT, "recvfrom");
libc_send = dlsym(RTLD_NEXT, "send");
libc_sendto = dlsym(RTLD_NEXT, "sendto");
libc_socket = dlsym(RTLD_NEXT, "socket");
libc_listen = dlsym(RTLD_NEXT, "listen");
}
int ioctl(int fd, unsigned long request, ...)
{
if (should_malloc_fail()) {
errno = ENOMEM;
return -1;
}
va_list ap;
va_start(ap, request);
const int ret = libc_ioctl(fd, SIOCGIFCONF, va_arg(ap, void *));
va_end(ap);
return ret;
}
int bind(int sockfd, const struct sockaddr *addr,
socklen_t addrlen)
{
// Unlike all others, if bind should fail once, it should fail always, because in toxcore we try
// many ports before giving up. If this only fails once, we'll never reach the code path where
// we give up.
static int should_fail = -1;
if (should_fail == -1) {
should_fail = should_malloc_fail();
}
if (should_fail) {
errno = ENOMEM;
return -1;
}
return libc_bind(sockfd, addr, addrlen);
}
int getsockopt(int sockfd, int level, int optname,
void *optval, socklen_t *optlen)
{
if (should_malloc_fail()) {
errno = ENOMEM;
return -1;
}
return libc_getsockopt(sockfd, level, optname, optval, optlen);
}
int setsockopt(int sockfd, int level, int optname,
const void *optval, socklen_t optlen)
{
if (should_malloc_fail()) {
errno = ENOMEM;
return -1;
}
return libc_setsockopt(sockfd, level, optname, optval, optlen);
}
ssize_t recv(int sockfd, void *buf, size_t len, int flags)
{
if (should_malloc_fail()) {
errno = ENOMEM;
return -1;
}
return libc_recv(sockfd, buf, len, flags);
}
ssize_t recvfrom(int sockfd, void *buf, size_t len, int flags,
struct sockaddr *src_addr, socklen_t *addrlen)
{
if (should_malloc_fail()) {
errno = ENOMEM;
return -1;
}
return libc_recvfrom(sockfd, buf, len, flags, src_addr, addrlen);
}
ssize_t send(int sockfd, const void *buf, size_t len, int flags)
{
if (should_malloc_fail()) {
errno = ENOMEM;
return -1;
}
return libc_send(sockfd, buf, len, flags);
}
ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
const struct sockaddr *dest_addr, socklen_t addrlen)
{
if (should_malloc_fail()) {
errno = ENOMEM;
return -1;
}
return libc_sendto(sockfd, buf, len, flags, dest_addr, addrlen);
}
int socket(int domain, int type, int protocol)
{
if (should_malloc_fail()) {
errno = ENOMEM;
return -1;
}
return libc_socket(domain, type, protocol);
}
int listen(int sockfd, int backlog)
{
if (should_malloc_fail()) {
errno = ENOMEM;
return -1;
}
return libc_listen(sockfd, backlog);
}

View File

@ -0,0 +1,18 @@
FROM alpine:latest AS build
ENV LANG=en_US.UTF-8 \
LANGUAGE=en_US.UTF-8 \
LC_CTYPE=en_US.UTF-8 \
LC_ALL=en_US.UTF-8
RUN apk add --no-cache doxygen git graphviz \
&& git clone --depth=1 https://github.com/jothepro/doxygen-awesome-css.git /work/doxygen-awesome-css
WORKDIR /work
COPY . /work/
RUN cat docs/Doxyfile > Doxyfile \
&& echo "WARN_AS_ERROR = YES" >> Doxyfile \
&& sed -i -e 's/^non_null([^)]*) *//;s/^nullable([^)]*) *//' $(find . -name "*.[ch]") \
&& doxygen Doxyfile
FROM nginx:alpine
COPY --from=build /work/_docs/html/ /usr/share/nginx/html/

View File

@ -0,0 +1,6 @@
#!/bin/sh
set -eux
docker build -t toxchat/c-toxcore:docs -f other/docker/doxygen/Dockerfile .
docker run --rm -it -p "28192:80" toxchat/c-toxcore:docs

View File

@ -0,0 +1,4 @@
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(toxcore)

View File

@ -0,0 +1,48 @@
FROM toxchat/c-toxcore:sources AS src
FROM ubuntu:18.04
RUN apt-get update && \
DEBIAN_FRONTEND="noninteractive" apt-get install -y --no-install-recommends \
bison \
ccache \
cmake \
flex \
git \
gperf \
libncurses-dev \
ninja-build \
python \
python-cryptography \
python-future \
python-pip \
python-pyparsing \
python-serial \
python-setuptools \
wget \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
ENV ESP32_TARBALL=xtensa-esp32-elf-linux64-1.22.0-80-g6c4433a-5.2.0 \
IDF_PATH="/root/esp/esp-idf" \
PATH="/root/esp/esp-idf/tools:/root/esp/xtensa-esp32-elf/bin:$PATH"
WORKDIR /root/esp
RUN wget -q https://dl.espressif.com/dl/$ESP32_TARBALL.tar.gz \
&& tar zxf $ESP32_TARBALL.tar.gz \
&& rm -f $ESP32_TARBALL.tar.gz \
&& git clone -b v3.3 --recursive --depth=1 --shallow-submodules https://github.com/espressif/esp-idf
# Build a hello world first, so the OS and libsodium etc. are compiled.
WORKDIR /root/esp/toxcore
COPY other/docker/esp32/CMakeLists.txt /root/esp/toxcore/
COPY other/docker/esp32/hello/ /root/esp/toxcore/main/
RUN idf.py build
# Then copy over the actual toxcore sources and build those.
COPY --from=src /src/third_party/cmp/ /root/esp/toxcore/main/third_party/cmp/
COPY --from=src /src/toxencryptsave/defines.h /root/esp/toxcore/main/toxencryptsave/
COPY --from=src /src/toxcore/ /root/esp/toxcore/main/toxcore/
COPY other/docker/esp32/toxcore/CMakeLists.txt /root/esp/toxcore/main/
COPY other/docker/esp32/toxcore/toxcore_main.cc /root/esp/toxcore/main/other/docker/esp32/main/
RUN idf.py build
RUN ls -lh build/toxcore.bin \
&& shasum build/toxcore.bin

View File

@ -0,0 +1,4 @@
set(COMPONENT_SRCS "hello_main.c")
set(COMPONENT_ADD_INCLUDEDIRS "")
register_component()

View File

@ -0,0 +1,6 @@
#include <stdio.h>
void app_main(void)
{
printf("Hello world!\n");
}

View File

@ -0,0 +1,4 @@
#!/bin/sh
docker build -t toxchat/c-toxcore:sources -f other/docker/sources/Dockerfile .
docker build -t toxchat/c-toxcore:esp32 -f other/docker/esp32/Dockerfile .

View File

@ -0,0 +1,12 @@
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-missing-field-initializers")
file(GLOB toxcore_SRCS "toxcore/*.[ch]" "toxcore/*/*.[ch]")
set(COMPONENT_SRCS
${toxcore_SRCS}
other/docker/esp32/main/toxcore_main.cc
third_party/cmp/cmp.c
third_party/cmp/cmp.h
toxencryptsave/defines.h)
set(COMPONENT_ADD_INCLUDEDIRS "")
register_component()

View File

@ -0,0 +1,14 @@
#include <stdio.h>
#include "../../../../toxcore/ccompat.h"
#include "../../../../toxcore/tox.h"
#include "../../../../toxcore/tox_events.h"
extern "C" void app_main(void)
{
printf("Hello Tox!\n");
Tox *tox = tox_new(nullptr, nullptr);
tox_events_free(tox_events_iterate(tox, true, nullptr));
tox_kill(tox);
}

View File

@ -0,0 +1 @@
!/Makefile

View File

@ -0,0 +1,20 @@
FROM ubuntu:20.04
RUN apt-get update && apt-get install --no-install-recommends -y \
ca-certificates \
cppcheck \
libopus-dev \
libsodium-dev \
libvpx-dev \
make \
wget \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
COPY toxav/ /src/workspace/c-toxcore/toxav/
COPY toxcore/ /src/workspace/c-toxcore/toxcore/
COPY toxencryptsave/ /src/workspace/c-toxcore/toxencryptsave/
COPY third_party/cmp/cmp.h /src/workspace/c-toxcore/third_party/cmp/cmp.h
COPY other/docker/misra/Makefile /src/workspace/
WORKDIR /src/workspace
RUN ["make"]

View File

@ -0,0 +1,166 @@
# See the following PDF for descriptions of each of the rules:
# http://my.ldrasoftware.co.uk/repository/miscellaneous/Misra-c_2012_compliance.pdf
# There should be no unused parameters in functions.
#
# Reason: callbacks often have unused parameters. Marking them explicitly isn't
# very helpful. A better diagnostic should be able to identify functions never
# used as callbacks and warn about unused parameters in those.
SUPPRESSIONS = 2.7
# The character sequences /* and // shall not be used within a comment.
#
# Reason: "//" appears in code examples and "http://" inside comments.
SUPPRESSIONS += 3.1
# Identifiers declared in the same scope and name space shall be distinct.
# Identifier not unique within 31 characters.
#
# Reason: Compilers we use allow longer identifier names.
SUPPRESSIONS += 5.2
# Macro identifiers shall be distinct.
# Identifier matches macro name in 31 chars.
#
# Reason: Compilers we use allow longer identifier names.
SUPPRESSIONS += 5.4
# The lowercase character 'l' shall not be used in a literal suffix.
#
# Reason: False positive. We don't use 'l', but this flags 'ulOutBufLen'.
SUPPRESSIONS += 7.3
# Operands shall not be of an inappropriate essential type.
#
# Reason: This diagnoses (1 << n) and wants us to use (1u << n). That's fair,
# but this diagnostic is impossible to fix for ((1u << n) >> m).
SUPPRESSIONS += 10.1
# Both operands of an operator in which the usual arithmetic conversions are performed shall have the same essential type category.
#
# Reason: This warns about ((unsigned)n == 0) and other constant comparisons.
SUPPRESSIONS += 10.4
# The value of a composite expression shall not be cast to a different essential type category or a wider essential type.
#
# TODO(iphydf): investigate.
SUPPRESSIONS += 10.8
# A conversion should not be performed from pointer to void into pointer to object.
#
# Reason: this is needed for generic callbacks to make any sense.
SUPPRESSIONS += 11.5
# The precedence of operators within expressions should be made explicit.
#
# Reason: this asks us to add a lot of extra parentheses that don't really help
# readability. We expect people to know basic precedence. GCC has a better
# diagnostic requiring parentheses around less common operators.
SUPPRESSIONS += 12.1
# The comma operator should not be used.
#
# Reason: We don't use the comma operator (cimple doesn't even parse it). This is
# all false positives.
SUPPRESSIONS += 12.3
# Evaluation of constant expressions should not lead to unsigned integer wrap-around.
#
# Reason: False positives on UINT64_MAX.
SUPPRESSIONS += 12.4
# A full expression containing an increment (++) or decrement (--) operator should have no other potential side effects other than that caused by the increment or decrement operator.
#
# TODO(iphydf): maybe fix?
SUPPRESSIONS += 13.3
# The controlling expression of an if statement and the controlling expression of an iteration-statement shall have essentially Boolean type.
#
# Reason: We actually follow this rule, but cppcheck's implementation is flawed and has false positives.
SUPPRESSIONS += 14.4
# The goto statement should not be used.
#
# TODO(iphydf): Get rid of goto.
SUPPRESSIONS += 15.1
# A function should have a single point of exit at the end.
#
# Reason: This doesn't make code much clearer. Sometimes this is useful for
# putting all the cleanup code in one spot, but often an early return improves
# readability.
SUPPRESSIONS += 15.5
# All if . . else if constructs shall be terminated with an else statement.
#
# TODO(iphydf): Why is this a good idea?
SUPPRESSIONS += 15.7
# An unconditional break statement shall terminate every switch-clause.
#
# Reason: This conflicts with "break unused after abort()". MISRA doesn't allow
# abort(), but we use it, so this rule must be disabled, too.
SUPPRESSIONS += 16.3
# Every switch statement shall have a default label.
#
# Reason: C compilers have better diagnostics for this (-Wswitch variants).
SUPPRESSIONS += 16.4
# The features of <stdarg.h> shall not be used.
#
# Reason: We use it for logging.
SUPPRESSIONS += 17.1
# Functions shall not call themselves, either directly or indirectly.
#
# Reason: Cimple is better at this diagnostic, recognising indirect recursion
# through callbacks.
SUPPRESSIONS += 17.2
# The value returned by a function having non-void return type shall be used.
#
# TODO(iphydf): Investigate.
SUPPRESSIONS += 17.7
# A function parameter should not be modified.
#
# TODO(iphydf): maybe fix?
SUPPRESSIONS += 17.8
# The +, -, += and -= operators should not be applied to an expression of pointer type.
# Use of pointer arithmetic.
#
# TODO(iphydf): Someday we won't be using pointer arithmetic.
SUPPRESSIONS += 18.4
# Flexible array members shall not be declared.
#
# TODO(iphydf): Fix.
SUPPRESSIONS += 18.7
# Variable-length array types shall not be used.
#
# TODO(iphydf): Fix.
SUPPRESSIONS += 18.8
# The union keyword should not be used.
#
# TODO(iphydf): Maybe we need a good linter to check that unions are used safely.
SUPPRESSIONS += 19.2
# #undef should not be used.
#
# Reason: We believe it should be used when #define is used in block scope.
SUPPRESSIONS += 20.5
# The # and ## preprocessor operators should not be used.
#
# TODO(iphydf): Remove suppression when VLAs are gone. This is only used in
# the SIZEOF_VLA macro.
SUPPRESSIONS += 20.10
# #define and #undef shall not be used on a reserved identifier or reserved macro name.
#
# Reason: Needed for feature test macros like _DEFAULT_SOURCE.
SUPPRESSIONS += 21.1
# The memory allocation and deallocation functions of <stdlib.h> shall not be used.
#
# Reason: We use malloc/free. Making our own allocators doesn't make the code
# safer.
SUPPRESSIONS += 21.3
# The Standard Library input/output routines shall not be used.
#
# Reason: Used in logging.
SUPPRESSIONS += 21.6
# The Standard Library termination functions of <stdlib.h> shall not be used.
# Use of abort, exit, etc.
#
# Reason: Used in LOGGER_FATAL.
SUPPRESSIONS += 21.8
# The Standard Library functions bsearch and qsort of <stdlib.h> shall not be used.
#
# TODO(iphydf): Why not use qsort?
SUPPRESSIONS += 21.9
# The Standard Library time and date routines shall not be used.
#
# TODO(iphydf): Probably stop using time().
SUPPRESSIONS += 21.10
CPPFLAGS := -DCMP_NO_FLOAT=1 -DMIN_LOGGER_LEVEL=LOGGER_LEVEL_TRACE
SOURCES := $(shell find /src/workspace/c-toxcore -name "*.c")
analyse: $(DUMPS:.dump=.diag)
cppcheck --error-exitcode=1 -j8 --addon=misra --suppress=doubleFree $(patsubst %,--suppress=misra-c2012-%,$(SUPPRESSIONS)) $(CPPFLAGS) $(SOURCES)

View File

@ -0,0 +1,3 @@
#!/bin/sh
docker build -f other/docker/misra/Dockerfile .

View File

@ -0,0 +1,15 @@
FROM alpine:3.14.0
RUN ["apk", "add", "--no-cache", \
"bash", \
"gcc", \
"linux-headers", \
"musl-dev", \
"libsodium-dev", \
"libvpx-dev", \
"opus-dev", \
"perf"]
WORKDIR /work
COPY other/docker/perf/entrypoint.sh /
ENTRYPOINT ["/entrypoint.sh"]

View File

@ -0,0 +1,23 @@
#!/usr/bin/env bash
set -eux
TEST=${1:-conference_test}
OUTPUT="/work/c-toxcore/test.perf"
readarray -t FLAGS <<<"$(pkg-config --cflags --libs libsodium opus vpx | sed -e 's/ /\n/g')"
readarray -t SRCS <<<"$(find /work/c-toxcore/tox* -name "*.c")"
gcc -pthread -g \
-o "/work/$TEST" -O3 -fno-omit-frame-pointer \
"${SRCS[@]}" \
/work/c-toxcore/auto_tests/auto_test_support.c \
/work/c-toxcore/testing/misc_tools.c \
"/work/c-toxcore/auto_tests/$TEST.c" \
-DMIN_LOGGER_LEVEL=LOGGER_LEVEL_TRACE \
"${FLAGS[@]}"
time perf record -g --call-graph dwarf --freq=max "/work/$TEST" /work/c-toxcore/auto_tests/
perf report | head -n50
perf script -F +pid >"$OUTPUT"
chown 1000:100 "$OUTPUT"

View File

@ -0,0 +1,9 @@
#!/bin/sh
set -eux
docker build -t toxchat/c-toxcore:perf -f other/docker/perf/Dockerfile .
docker run --privileged --rm -it \
-v "$PWD:/work/c-toxcore" \
toxchat/c-toxcore:perf \
"$@"

View File

@ -0,0 +1,17 @@
FROM scratch
# Roughly in order of change frequency.
COPY third_party/ /src/third_party/
COPY .github/scripts/flags*.sh /src/.github/scripts/
COPY other/proxy/ /src/other/proxy/
COPY cmake/ /src/cmake/
COPY other/bootstrap_daemon/ /src/other/bootstrap_daemon/
COPY other/pkgconfig/ /src/other/pkgconfig/
COPY other/rpm/ /src/other/rpm/
COPY other/*.[ch] /src/other/
COPY CMakeLists.txt so.version /src/
COPY toxencryptsave/ /src/toxencryptsave/
COPY testing/ /src/testing/
COPY toxav/ /src/toxav/
COPY toxcore/ /src/toxcore/
COPY auto_tests/ /src/auto_tests/

View File

@ -0,0 +1,47 @@
FROM ubuntu:20.04
RUN apt-get update && \
DEBIAN_FRONTEND="noninteractive" apt-get install -y --no-install-recommends \
libc-dev \
libopus-dev \
libsodium-dev \
libvpx-dev \
pkg-config \
tcc \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /work
COPY auto_tests/ /work/auto_tests/
COPY testing/ /work/testing/
COPY toxav/ /work/toxav/
COPY toxcore/ /work/toxcore/
COPY toxencryptsave/ /work/toxencryptsave/
RUN tcc \
-Dinline=static \
-o send_message_test \
-Wall -Werror \
-bench -g \
auto_tests/auto_test_support.c \
auto_tests/send_message_test.c \
testing/misc_tools.c \
toxav/*.c \
toxcore/*.c \
toxcore/*/*.c \
toxencryptsave/*.c \
third_party/cmp/*.c \
$(pkg-config --cflags --libs libsodium opus vpx)
SHELL ["/bin/bash", "-o", "pipefail", "-c"]
COPY other/make_single_file /work/other/
RUN \
other/make_single_file \
auto_tests/auto_test_support.c \
auto_tests/send_message_test.c \
testing/misc_tools.c | \
tcc - \
-o send_message_test \
-Wall -Werror \
-bench -g \
$(pkg-config --cflags --libs libsodium opus vpx)

View File

@ -0,0 +1,5 @@
#!/bin/sh
set -eux
docker build -t toxchat/c-toxcore:tcc -f other/docker/tcc/Dockerfile .

View File

@ -0,0 +1,21 @@
FROM toxchat/haskell:hs-tokstyle AS tokstyle
FROM ubuntu:20.04
RUN apt-get update && apt-get install --no-install-recommends -y \
ca-certificates \
clang \
git \
libopus-dev \
libsodium-dev \
libvpx-dev \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*
COPY --from=tokstyle /bin/check-c /bin/
RUN ["git", "clone", "--depth=1", "https://github.com/TokTok/hs-tokstyle", "/src/workspace/hs-tokstyle"]
COPY toxav/ /src/workspace/c-toxcore/toxav/
COPY toxcore/ /src/workspace/c-toxcore/toxcore/
COPY toxencryptsave/ /src/workspace/c-toxcore/toxencryptsave/
COPY third_party/cmp/cmp.h /src/workspace/c-toxcore/third_party/cmp/cmp.h
RUN /bin/check-c $(find /src/workspace/c-toxcore -name "*.c")

View File

@ -0,0 +1,3 @@
#!/bin/sh
docker build -f other/docker/tokstyle/Dockerfile .

View File

@ -0,0 +1,35 @@
FROM debian:bullseye-slim
# Build-time environment variables
ARG VERSION_MSGPACK=4.0.0 \
VERSION_SODIUM=1.0.18 \
VERSION_OPUS=1.3.1 \
VERSION_VPX=1.11.0 \
\
SUPPORT_TEST=false \
SUPPORT_ARCH_i686=true \
SUPPORT_ARCH_x86_64=true \
CROSS_COMPILE=true
# Make those available when running the container
ENV SUPPORT_TEST=${SUPPORT_TEST} \
SUPPORT_ARCH_i686=${SUPPORT_ARCH_i686} \
SUPPORT_ARCH_x86_64=${SUPPORT_ARCH_x86_64} \
CROSS_COMPILE=${CROSS_COMPILE}
WORKDIR /work
COPY get_packages.sh .
RUN ./get_packages.sh
COPY build_dependencies.sh .
RUN ./build_dependencies.sh
COPY build_toxcore.sh .
ENV ENABLE_TEST=false \
ALLOW_TEST_FAILURE=false \
ENABLE_ARCH_i686=true \
ENABLE_ARCH_x86_64=true \
EXTRA_CMAKE_FLAGS="-DTEST_TIMEOUT_SECONDS=90"
ENTRYPOINT ["bash", "./build_toxcore.sh"]

View File

@ -0,0 +1,97 @@
#!/usr/bin/env bash
# disable on Cygwin otherwise some builds fail
if [ "$CROSS_COMPILE" = "true" ]; then
set -e -x
fi
#=== Cross-Compile Dependencies ===
build() {
ARCH=${1}
echo "Building for $ARCH architecture"
# set some things
WINDOWS_TOOLCHAIN=$ARCH-w64-mingw32
# prefix that we will copy to the user
PREFIX_DIR="/root/prefix/$ARCH"
rm -rf "$PREFIX_DIR"
mkdir -p "$PREFIX_DIR"
export MAKEFLAGS=j"$(nproc)"
export CFLAGS=-O3
CURL_OPTIONS=(-L --connect-timeout 10)
cd /tmp
rm -rf /tmp/*
echo "
SET(CMAKE_SYSTEM_NAME Windows)
SET(CMAKE_C_COMPILER $WINDOWS_TOOLCHAIN-gcc)
SET(CMAKE_CXX_COMPILER $WINDOWS_TOOLCHAIN-g++)
SET(CMAKE_RC_COMPILER $WINDOWS_TOOLCHAIN-windres)
SET(CMAKE_FIND_ROOT_PATH /usr/$WINDOWS_TOOLCHAIN $DEP_PREFIX_DIR)
" >windows_toolchain.cmake
echo
echo "=== Building Sodium $VERSION_SODIUM $ARCH ==="
curl "${CURL_OPTIONS[@]}" -O "https://download.libsodium.org/libsodium/releases/libsodium-$VERSION_SODIUM.tar.gz"
tar -xf "libsodium-$VERSION_SODIUM.tar.gz"
cd "libsodium-$VERSION_SODIUM"
./configure --host="$WINDOWS_TOOLCHAIN" --prefix="$PREFIX_DIR" --disable-shared --enable-static
make
make install
cd ..
echo
echo "=== Building Opus $VERSION_OPUS $ARCH ==="
curl "${CURL_OPTIONS[@]}" -O "https://archive.mozilla.org/pub/opus/opus-$VERSION_OPUS.tar.gz"
tar -xf "opus-$VERSION_OPUS.tar.gz"
cd "opus-$VERSION_OPUS"
./configure --host="$WINDOWS_TOOLCHAIN" --prefix="$PREFIX_DIR" --disable-extra-programs --disable-doc --disable-shared --enable-static
make
make install
cd ..
echo
echo "=== Building VPX $VERSION_VPX $ARCH ==="
LIB_VPX_TARGET=""
if [ "$ARCH" = "i686" ]; then
LIB_VPX_TARGET=x86-win32-gcc
LIB_VPX_CFLAGS=""
else
LIB_VPX_TARGET=x86_64-win64-gcc
# There is a bug in gcc that breaks avx512 on 64-bit Windows https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54412
# VPX fails to build due to it.
# This is a workaround as suggested in https://stackoverflow.com/questions/43152633
LIB_VPX_CFLAGS="-fno-asynchronous-unwind-tables"
fi
curl "${CURL_OPTIONS[@]}" "https://github.com/webmproject/libvpx/archive/v$VERSION_VPX.tar.gz" -o "libvpx-$VERSION_VPX.tar.gz"
tar -xf "libvpx-$VERSION_VPX.tar.gz"
cd "libvpx-$VERSION_VPX"
CFLAGS="$LIB_VPX_CFLAGS" CROSS="$WINDOWS_TOOLCHAIN"- ./configure --target="$LIB_VPX_TARGET" --prefix="$PREFIX_DIR" --disable-examples --disable-unit-tests --disable-shared --enable-static
make
make install
cd ..
rm -rf /tmp/*
}
if [ "$SUPPORT_ARCH_i686" = "true" ]; then
build i686
fi
if [ "$SUPPORT_ARCH_x86_64" = "true" ]; then
build x86_64
fi
tree /root
echo
echo "Built dependencies successfully!"
echo

View File

@ -0,0 +1,189 @@
#!/usr/bin/env bash
set -e -x
#=== Cross-Compile Toxcore ===
build() {
ARCH=${1}
echo "Building for $ARCH architecture"
# set some things
WINDOWS_TOOLCHAIN=$ARCH-w64-mingw32
# toxcore dependencies that we will copy to the user for static build of toxcore (e.g. vpx, opus, sodium)
DEP_PREFIX_DIR="/root/prefix/$ARCH"
# where to put the result of this particular build
RESULT_PREFIX_DIR="/prefix/$ARCH"
rm -rf "$RESULT_PREFIX_DIR"
mkdir -p "$RESULT_PREFIX_DIR"
rm -rf /tmp/*
# where to install static/shared toxcores before deciding whether they should be copied over to the user
STATIC_TOXCORE_PREFIX_DIR="/tmp/static_prefix"
SHARED_TOXCORE_PREFIX_DIR="/tmp/shared_prefix"
mkdir -p "$STATIC_TOXCORE_PREFIX_DIR" "$SHARED_TOXCORE_PREFIX_DIR"
export MAKEFLAGS=j"$(nproc)"
export CFLAGS=-O3
echo
echo "=== Building toxcore $ARCH ==="
export PKG_CONFIG_PATH="$DEP_PREFIX_DIR/lib/pkgconfig"
if [ "$CROSS_COMPILE" = "true" ]; then
TOXCORE_DIR="/toxcore"
else
# get Toxcore root
cd "$(cd "$(dirname -- "$0")" >/dev/null 2>&1 && pwd)"
cd ../../../
TOXCORE_DIR="$PWD"
fi
cp -a "$TOXCORE_DIR" /tmp/toxcore
cd /tmp/toxcore/build
echo "
SET(CMAKE_SYSTEM_NAME Windows)
SET(CMAKE_C_COMPILER $WINDOWS_TOOLCHAIN-gcc)
SET(CMAKE_CXX_COMPILER $WINDOWS_TOOLCHAIN-g++)
SET(CMAKE_RC_COMPILER $WINDOWS_TOOLCHAIN-windres)
SET(CMAKE_FIND_ROOT_PATH /usr/$WINDOWS_TOOLCHAIN $DEP_PREFIX_DIR)
" >windows_toolchain.cmake
if [ "$ENABLE_TEST" = "true" ]; then
echo "SET(CROSSCOMPILING_EMULATOR /usr/bin/wine)" >>windows_toolchain.cmake
fi
# Silly way to bypass a shellharden check
read -ra EXTRA_CMAKE_FLAGS_ARRAY <<<"$EXTRA_CMAKE_FLAGS"
cmake -DCMAKE_TOOLCHAIN_FILE=windows_toolchain.cmake \
-DCMAKE_INSTALL_PREFIX="$STATIC_TOXCORE_PREFIX_DIR" \
-DENABLE_SHARED=OFF \
-DENABLE_STATIC=ON \
-DCMAKE_C_FLAGS="$CMAKE_C_FLAGS" \
-DCMAKE_CXX_FLAGS="$CMAKE_CXX_FLAGS" \
-DCMAKE_EXE_LINKER_FLAGS="$CMAKE_EXE_LINKER_FLAGS -fstack-protector" \
-DCMAKE_SHARED_LINKER_FLAGS="$CMAKE_SHARED_LINKER_FLAGS" \
"${EXTRA_CMAKE_FLAGS_ARRAY[@]}" \
-S ..
cmake --build . --target install -- -j"$(nproc)"
if [ "$ENABLE_TEST" = "true" ]; then
rm -rf /root/.wine
# setup wine
if [ "$ARCH" = "i686" ]; then
export WINEARCH=win32
else
export WINEARCH=win64
fi
winecfg
export CTEST_OUTPUT_ON_FAILURE=1
# add libgcc_s_sjlj-1.dll libwinpthread-1.dll into PATH env var of wine
export WINEPATH="$(
cd /usr/lib/gcc/"$WINDOWS_TOOLCHAIN"/*posix/
winepath -w "$PWD"
)"\;"$(winepath -w /usr/"$WINDOWS_TOOLCHAIN"/lib/)"
if [ "$ALLOW_TEST_FAILURE" = "true" ]; then
set +e
fi
cmake --build . --target test -- ARGS="-j50"
if [ "$ALLOW_TEST_FAILURE" = "true" ]; then
set -e
fi
fi
# move static dependencies
cp -a "$STATIC_TOXCORE_PREFIX_DIR"/* "$RESULT_PREFIX_DIR"
cp -a "$DEP_PREFIX_DIR"/* "$RESULT_PREFIX_DIR"
# make libtox.dll
cd "$SHARED_TOXCORE_PREFIX_DIR"
for archive in "$STATIC_TOXCORE_PREFIX_DIR"/lib/libtox*.a; do
"$WINDOWS_TOOLCHAIN"-ar xv "$archive"
done
if [ "$CROSS_COMPILE" = "true" ]; then
LIBWINPTHREAD="/usr/$WINDOWS_TOOLCHAIN/lib/libwinpthread.a"
else
LIBWINPTHREAD="/usr/$WINDOWS_TOOLCHAIN/sys-root/mingw/lib/libwinpthread.a"
fi
"$WINDOWS_TOOLCHAIN"-gcc -Wl,--export-all-symbols \
-Wl,--out-implib=libtox.dll.a \
-shared \
-o libtox.dll \
*.obj \
"$STATIC_TOXCORE_PREFIX_DIR"/lib/*.a \
"$DEP_PREFIX_DIR"/lib/*.a \
"$LIBWINPTHREAD" \
-liphlpapi \
-lws2_32 \
-static-libgcc \
-lssp
cp libtox.dll.a "$RESULT_PREFIX_DIR"/lib
mkdir -p "$RESULT_PREFIX_DIR"/bin
cp libtox.dll "$RESULT_PREFIX_DIR"/bin
rm -rf /tmp/*
# remove everything from include directory except tox headers
mv "$RESULT_PREFIX_DIR"/include/tox "$RESULT_PREFIX_DIR"/tox
rm -rf "$RESULT_PREFIX_DIR"/include/*
mv "$RESULT_PREFIX_DIR"/tox "$RESULT_PREFIX_DIR"/include/tox
sed -i "s|^prefix=.*|prefix=$RESULT_PREFIX_DIR|g" "$RESULT_PREFIX_DIR"/lib/pkgconfig/*.pc
sed -i "s|^libdir=.*|libdir=$RESULT_PREFIX_DIR/lib|g" "$RESULT_PREFIX_DIR"/lib/*.la
}
#=== Test Supported vs. Enabled ===
if [ "$ENABLE_ARCH_i686" != "true" ] && [ "$ENABLE_ARCH_x86_64" != "true" ]; then
echo "Error: No architecture specified. Set either ENABLE_ARCH_i686 or ENABLE_ARCH_x86_64 or both."
exit 1
fi
if [ "$ENABLE_ARCH_i686" = "true" ] && [ "$SUPPORT_ARCH_i686" != "true" ]; then
echo "Error: Can't build for i686 architecture because the image was created without SUPPORT_ARCH_i686 set"
exit 1
fi
if [ "$ENABLE_ARCH_x86_64" = "true" ] && [ "$SUPPORT_ARCH_x86_64" != "true" ]; then
echo "Error: Can't build for x86_64 architecture because the image was created without SUPPORT_ARCH_x86_64 set"
exit 1
fi
if [ "$ENABLE_TEST" = "true" ] && [ "$SUPPORT_TEST" != "true" ]; then
echo "Error: Can't build with tests because the image was created without SUPPORT_TEST set"
exit 1
fi
#=== Build ===
if [ "$ENABLE_ARCH_i686" = "true" ]; then
build i686
fi
if [ "$ENABLE_ARCH_x86_64" = "true" ]; then
build x86_64
fi
tree -h /prefix
echo
echo "Built toxcore successfully!"
echo
# since we are building as root
if [ "$CROSS_COMPILE" = "true" ]; then
chmod 777 /prefix -R
fi

View File

@ -0,0 +1,54 @@
#!/usr/bin/env sh
set -e -x
#=== Install Packages ===
apt-get update
# Arch-independent packages required for building toxcore's dependencies and toxcore itself
apt-get install -y \
autoconf \
automake \
ca-certificates \
cmake \
curl \
libtool \
libc-dev \
make \
pkg-config \
tree \
yasm
# Arch-dependent packages required for building toxcore's dependencies and toxcore itself
if [ "$SUPPORT_ARCH_i686" = "true" ]; then
apt-get install -y \
g++-mingw-w64-i686 \
gcc-mingw-w64-i686
fi
if [ "$SUPPORT_ARCH_x86_64" = "true" ]; then
apt-get install -y \
g++-mingw-w64-x86-64 \
gcc-mingw-w64-x86-64
fi
# Packages needed for running toxcore tests
if [ "$SUPPORT_TEST" = "true" ]; then
apt-get install -y \
texinfo
dpkg --add-architecture i386
apt-get update
apt-get install -y \
wine \
wine32 \
wine64
fi
# Clean up to reduce image size
apt-get clean
rm -rf \
/var/lib/apt/lists/* \
/tmp/* \
/var/tmp/*