Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/70.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在arm上的docker容器中运行C musl应用程序时出现时间()问题_C_Docker_Arm_Alpine_Musl - Fatal编程技术网

在arm上的docker容器中运行C musl应用程序时出现时间()问题

在arm上的docker容器中运行C musl应用程序时出现时间()问题,c,docker,arm,alpine,musl,C,Docker,Arm,Alpine,Musl,我的应用程序无法处理时间操作,比如在arm设备上的alpine docker容器中运行时 我所拥有的: 我正在构建一个本机c应用程序,它通过musl.cc(arm linux musleabihf gcc)中的工具链静态链接到musl。我使用的是最新的阿尔卑斯山集装箱(没有图像标签) 其行为方式: 直接在arm设备上运行二进制文件可以正常工作 在x64设备上的alpine容器中运行,工作正常 在手臂装置上的阿尔卑斯山容器中运行不起作用 出了什么问题: 时间(空)返回((时间)-1)且错误=

我的应用程序无法处理时间操作,比如在arm设备上的alpine docker容器中运行时

我所拥有的: 我正在构建一个本机c应用程序,它通过musl.cc(arm linux musleabihf gcc)中的工具链静态链接到musl。我使用的是最新的阿尔卑斯山集装箱(没有图像标签)

其行为方式:

  • 直接在arm设备上运行二进制文件可以正常工作
  • 在x64设备上的alpine容器中运行,工作正常
  • 在手臂装置上的阿尔卑斯山容器中运行不起作用
出了什么问题:

  • 时间(空)返回((时间)-1)且错误=1:“不允许操作”
  • 日志输出中的时间戳具有启动时间戳
  • SSH握手失败,因为远程证书的有效性在将来
但是,如果在容器的ash中执行
date
,则输出有效。因此,似乎只有在ARM架构上的alpine容器中才会出现问题。有趣的是,我正从Ubuntu切换到阿尔卑斯山

有人知道我做错了什么吗

更新#1: ubuntu上也有同样的问题。因此,问题似乎出现在任何docker基础上的图像上,但仅出现在arm设备上

更新#2:下面是一个简单的例子 TimeTest.c

#include <stdio.h>
#include <string.h>
#include "time.h"
#include "errno.h"

int main()
{
    printf("hallo\n");

    time_t myTime;
    time_t result = time(&myTime);

    printf("result: %lld\n", result);

    if ((long)result < 0)
    {
        printf("time() error=%d: %s\n", errno, strerror(errno));
    }
    else
    {
        struct tm* tm_info = localtime(&myTime);
        printf("Current local time and date: %s\n", asctime(tm_info));
    }

    return 0;
}
#include <time.h>
#include <errno.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/syscall.h>

static bool __wrap___clock_gettime_fallback = false;

int __wrap___clock_gettime(clockid_t clk, struct timespec* ts)
{
    int r;

    if (!__wrap___clock_gettime_fallback)
    {
        r = __real___clock_gettime(clk, ts);
        if (!r) return r;

        if (errno == EPERM || errno == EINVAL)
        {
            printf("WARN: clock_gettime() faulted with '%s'. Using SYS_clock_gettime32 as permanent fallback. Possible cause could be a faulty Docker version!\n", strerror(errno));
            __wrap___clock_gettime_fallback = true;     // skip in future
        }
    }

    long ts32[2];
    r = syscall(SYS_clock_gettime32, clk, ts32);
    if (r == -ENOSYS && clk == CLOCK_REALTIME) {
        r = syscall(SYS_gettimeofday_time32, ts32, 0);
        ts32[1] *= 1000;
    }
    if (!r) {
        ts->tv_sec = ts32[0];
        ts->tv_nsec = ts32[1];
    }
    return r;
}

int __attribute__((weak, alias("__wrap___clock_gettime"))) clock_gettime(clockid_t clk, struct timespec* ts);
arm设备上的输出

pi@raspberrypi:/tmp $ docker run --rm -it -v /tmp/TimeTest:/TimeTest alpine ash
/ # /TimeTest
hallo
result: -4696377169665647048
time() error=1: Operation not permitted

我能够完全按照问题中的描述重现这一点。在我的特定ARM硬件上:

$ docker --version
Docker version 19.03.6, build 369ce74a3c [released approx. 2020-02-12]

$ file demo
demo: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV),
statically linked, with debug_info, not stripped
使用
strace
我们可以在按报告启动的容器内观察到这种行为:

...
clock_gettime64(CLOCK_REALTIME, 0xbe9c5e10) = -1 EPERM (Operation not permitted)
...
但是,如果我们将
--privileged
标志添加到Docker命令中,它将起作用:

# ./demo
hallo
result: 1608983884
Current local time and date: Sat Dec 26 11:58:04 2020

此行为是由Docker问题引起的,该问题已在Docker版本
19.03.12
(?)及以上版本中修复并滚动。ionFish解决了此难题。我将在他的帖子上注明答案。然而,我想发布一个可能的解决办法,我认为应该在所有情况下都有效。你们觉得怎么样

我为创建了一个包装器,并始终回退到gettime32

DockerFix.c

#include <stdio.h>
#include <string.h>
#include "time.h"
#include "errno.h"

int main()
{
    printf("hallo\n");

    time_t myTime;
    time_t result = time(&myTime);

    printf("result: %lld\n", result);

    if ((long)result < 0)
    {
        printf("time() error=%d: %s\n", errno, strerror(errno));
    }
    else
    {
        struct tm* tm_info = localtime(&myTime);
        printf("Current local time and date: %s\n", asctime(tm_info));
    }

    return 0;
}
#include <time.h>
#include <errno.h>
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/syscall.h>

static bool __wrap___clock_gettime_fallback = false;

int __wrap___clock_gettime(clockid_t clk, struct timespec* ts)
{
    int r;

    if (!__wrap___clock_gettime_fallback)
    {
        r = __real___clock_gettime(clk, ts);
        if (!r) return r;

        if (errno == EPERM || errno == EINVAL)
        {
            printf("WARN: clock_gettime() faulted with '%s'. Using SYS_clock_gettime32 as permanent fallback. Possible cause could be a faulty Docker version!\n", strerror(errno));
            __wrap___clock_gettime_fallback = true;     // skip in future
        }
    }

    long ts32[2];
    r = syscall(SYS_clock_gettime32, clk, ts32);
    if (r == -ENOSYS && clk == CLOCK_REALTIME) {
        r = syscall(SYS_gettimeofday_time32, ts32, 0);
        ts32[1] *= 1000;
    }
    if (!r) {
        ts->tv_sec = ts32[0];
        ts->tv_nsec = ts32[1];
    }
    return r;
}

int __attribute__((weak, alias("__wrap___clock_gettime"))) clock_gettime(clockid_t clk, struct timespec* ts);

在黑暗中拍摄猜测:可能与此有关。如果使用
time\t
对象的地址调用
time()
,会发生什么情况?@AndrewHenle:返回值和指向time()的时间都具有相同的值:((time\t)-1)您可以发布示例程序吗<代码>是静态链接的
呃,正常链接也会发生同样的情况吗?你能发布你正在使用的编译命令吗?卡米尔库克:我加了一个例子。希望这个例子是好的,非常感谢。这真是个烦人的问题。恐怕我需要在这附近工作。您认为
\uu clock\u gettime()
的包装器怎么样?