Skip to content

Commit 2cef080

Browse files
committed
Implement check glibstdc++
1 parent a9a910d commit 2cef080

File tree

9 files changed

+192
-34
lines changed

9 files changed

+192
-34
lines changed

src/check-runtime/check-libstdc++.cpp

Lines changed: 0 additions & 30 deletions
This file was deleted.

src/modules/CMakeLists.txt

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
add_executable(check-glibc check-glibc.c)
1+
add_library(module_common OBJECT common.c)
2+
3+
add_executable(check-glibc check-glibc.c $<TARGET_OBJECTS:module_common>)
24
target_link_libraries(check-glibc PRIVATE libconfig common_objects)
35

4-
add_executable(check-glibstdc++ check-glibstdc++.cpp)
6+
add_executable(check-glibstdc++ check-glibstdc++.cpp $<TARGET_OBJECTS:module_common>)
7+
target_link_libraries(check-glibstdc++ PRIVATE libconfig common_objects)
58
target_compile_options(check-glibstdc++ PUBLIC $<$<COMPILE_LANGUAGE:CXX>:-std=c++11>)
69

710
# check-glibstdc++ was written using the least amount of c++ in order to ensure backward compatibility with Centos 6

src/modules/check-glibstdc++.cpp

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
#include <link.h>
2+
#include <cstdlib>
3+
#include <regex.h>
4+
#include <cstring>
5+
#include <libconfig.h>
6+
7+
#ifdef __cplusplus
8+
extern "C"
9+
{
10+
#endif
11+
12+
#include "common.h"
13+
#include "common/string_utils.h"
14+
15+
#ifdef __cplusplus
16+
}
17+
#endif
18+
19+
typedef struct {
20+
regex_t regex;
21+
char* version;
22+
} extract_libstdcpp_version_ctx_t;
23+
24+
static int extract_libstdcpp_version(struct dl_phdr_info* info, size_t, void* data) {
25+
regmatch_t match[2] = {0x0};
26+
auto* ctx = (extract_libstdcpp_version_ctx_t*) data;
27+
char* real_so_path = realpath(info->dlpi_name, nullptr);
28+
29+
if (real_so_path != NULL && regexec(&ctx->regex, real_so_path, 2, match, 0) == 0) {
30+
char* version = strndup(real_so_path + match[1].rm_so, match[1].rm_eo - match[1].rm_so);
31+
ctx->version = version;
32+
return 1;
33+
}
34+
35+
return 0;
36+
}
37+
38+
char* extract_libstdcpp_version_from_runtime_libaries_paths() {
39+
extract_libstdcpp_version_ctx_t extract_libstdcpp_version_ctx = {nullptr};
40+
41+
if (regcomp(&extract_libstdcpp_version_ctx.regex, R"(libstdc\+\+\.so\.([0-9]+\.[0-9]+(\.[0-9]+)?))",
42+
REG_EXTENDED) != 0) {
43+
printf("Regex compilation error.");
44+
exit(EXIT_FAILURE);
45+
}
46+
47+
// iterate over the loaded libraries to resolve their paths and guess the libstdc++ version from it
48+
dl_iterate_phdr(extract_libstdcpp_version, &extract_libstdcpp_version_ctx);
49+
return extract_libstdcpp_version_ctx.version;
50+
}
51+
52+
char* read_required_glibstdcpp_version_from_config(char* config_path) {
53+
config_t cfg;
54+
const char* str;
55+
56+
config_init(&cfg);
57+
58+
/* Read the file. If there is an error, report it and exit. */
59+
if (!config_read_file(&cfg, config_path)) {
60+
fprintf(stderr, "ERROR:check-glibstdc++: %s:%d - %s\n", config_error_file(&cfg), config_error_line(&cfg),
61+
config_error_text(&cfg));
62+
config_destroy(&cfg);
63+
exit(EXIT_FAILURE);
64+
}
65+
66+
if (!config_lookup_string(&cfg, "check.required_glibstdcpp", &str)) {
67+
fprintf(stderr, "ERROR:check-glibstdc++: missing config entry 'check.required_glibstdcpp'");
68+
exit(EXIT_FAILURE);
69+
}
70+
71+
char* glibstdcpp_version = strdup(str);
72+
73+
config_destroy(&cfg);
74+
return glibstdcpp_version;
75+
}
76+
77+
int main(int, char* []) {
78+
char* system_version = extract_libstdcpp_version_from_runtime_libaries_paths();
79+
80+
char* config_path = resolve_module_config_path();
81+
char* required_version = read_required_glibstdcpp_version_from_config(config_path);
82+
83+
// the libc module must be used if the system version is lesser than the required
84+
if (compare_version_strings(system_version, required_version) > 0)
85+
return EXIT_SUCCESS;
86+
else
87+
return EXIT_FAILURE;
88+
}

src/modules/common.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
#include <unistd.h>
2+
#include <string.h>
3+
#include <stdlib.h>
4+
#include <stdio.h>
5+
6+
#include "common.h"
7+
8+
char* resolve_module_config_path() {
9+
char* path = malloc(FILENAME_MAX * sizeof(char));
10+
if (realpath("/proc/self/exe", path) == NULL) {
11+
fprintf(stderr, "ERROR:check-libc: Unable to find binary location");
12+
exit(EXIT_FAILURE);
13+
}
14+
15+
// replace binary name by 'config'
16+
char* dir_slash_idx = strrchr(path, '/');
17+
*dir_slash_idx = 0;
18+
strcat(dir_slash_idx, "/config");
19+
if (access(path, F_OK) != 0) {
20+
fprintf(stderr, "ERROR:check-libc: Unable to find the config file at: %s", path);
21+
exit(EXIT_FAILURE);
22+
}
23+
24+
return path;
25+
}

src/modules/common.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#ifndef APPIMAGEEXECWRAPPER_COMMON_H
2+
#define APPIMAGEEXECWRAPPER_COMMON_H
3+
4+
5+
char* resolve_module_config_path();
6+
7+
#endif //APPIMAGEEXECWRAPPER_COMMON_H

test/modules/CMakeLists.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
11
add_test(
22
NAME TEST_CHECK_GLIBC
33
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test-check-glibc.sh $<TARGET_FILE:check-glibc>
4+
)
5+
6+
add_test(
7+
NAME TEST_CHECK_GLIBSTDCPP
8+
COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/test-check-glibstdc++.sh $<TARGET_FILE:check-glibstdc++>
49
)

test/modules/common.sh

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#!/bin/bash
2+
3+
function assert_success() {
4+
if $@; then
5+
echo " [PASS]"
6+
else
7+
echo " [FAIL]"
8+
exit 1
9+
fi
10+
}
11+
12+
function assert_fail() {
13+
if $@; then
14+
echo " [FAIL]"
15+
exit 1
16+
else
17+
echo " [PASS]"
18+
fi
19+
}

test/modules/test-check-glibc.sh

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,14 +23,16 @@ check:
2323
EOF
2424
}
2525

26+
source $(dirname $0)/common.sh
27+
2628
###############
2729
## TEST CASES #
2830
###############
2931

3032
printf "Check on system glibc higher than required, expected ZERO as return value"
3133
setup_test_case "$TEST_DIR/test-check-glibc-with-lower-requirement" "1.0.0"
32-
"$TEST_DIR/test-check-glibc-with-lower-requirement/check" && echo " PASS"
34+
assert_success "$TEST_DIR/test-check-glibc-with-lower-requirement/check"
3335

3436
printf "Check on system glibc lower than required, expected NON ZERO as return value"
3537
setup_test_case "$TEST_DIR/test-check-glibc-with-lower-requirement" "9999.0.0"
36-
! "$TEST_DIR/test-check-glibc-with-lower-requirement/check" && echo " PASS"
38+
assert_fail "$TEST_DIR/test-check-glibc-with-lower-requirement/check"
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
#!/bin/bash
2+
3+
set -e
4+
5+
TEST_DIR="$PWD"
6+
CHECK_GLIBSTDCPP_BIN=$1
7+
if [ -z "$CHECK_GLIBSTDCPP_BIN" ]; then
8+
echo "Missing CHECK_GLIBSTDCPP_BIN"
9+
exit 1
10+
fi
11+
12+
function setup_test_case() {
13+
TARGET_DIR=$1
14+
REQUIRED_GLIBSTDCPP=$2
15+
mkdir -p "$TARGET_DIR"
16+
cp "$CHECK_GLIBSTDCPP_BIN" "$TARGET_DIR/check"
17+
cat >"$TARGET_DIR/config" <<EOF
18+
version = "1.0";
19+
check:
20+
{
21+
required_glibstdcpp = "$REQUIRED_GLIBSTDCPP";
22+
};
23+
EOF
24+
}
25+
26+
source $(dirname $0)/common.sh
27+
28+
29+
###############
30+
## TEST CASES #
31+
###############
32+
33+
printf "Check on system glibstdc++ higher than required, expected ZERO as return value"
34+
setup_test_case "$TEST_DIR/test-check-glibstdc++-with-lower-requirement" "1.0.0"
35+
assert_success "$TEST_DIR/test-check-glibstdc++-with-lower-requirement/check"
36+
37+
printf "Check on system glibstdc++ lower than required, expected NON ZERO as return value"
38+
setup_test_case "$TEST_DIR/test-check-glibstdc++-with-lower-requirement" "9999.0.0"
39+
assert_fail "$TEST_DIR/test-check-glibstdc++-with-lower-requirement/check"

0 commit comments

Comments
 (0)