Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions libc/config/baremetal/arm/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.time.asctime_r
libc.src.time.ctime
libc.src.time.ctime_r
libc.src.time.ctime_s
libc.src.time.difftime
libc.src.time.gmtime
libc.src.time.gmtime_r
Expand Down
1 change: 1 addition & 0 deletions libc/config/baremetal/riscv/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ set(TARGET_LIBC_ENTRYPOINTS
libc.src.time.asctime_r
libc.src.time.ctime
libc.src.time.ctime_r
libc.src.time.ctime_s
libc.src.time.difftime
libc.src.time.gmtime
libc.src.time.gmtime_r
Expand Down
1 change: 1 addition & 0 deletions libc/config/linux/aarch64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.time.asctime_r
libc.src.time.ctime
libc.src.time.ctime_r
libc.src.time.ctime_s
libc.src.time.clock
libc.src.time.clock_gettime
libc.src.time.difftime
Expand Down
1 change: 1 addition & 0 deletions libc/config/linux/riscv/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -941,6 +941,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.time.asctime_r
libc.src.time.ctime
libc.src.time.ctime_r
libc.src.time.ctime_s
libc.src.time.clock
libc.src.time.clock_gettime
libc.src.time.difftime
Expand Down
1 change: 1 addition & 0 deletions libc/config/linux/x86_64/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1095,6 +1095,7 @@ if(LLVM_LIBC_FULL_BUILD)
libc.src.time.asctime_r
libc.src.time.ctime
libc.src.time.ctime_r
libc.src.time.ctime_s
libc.src.time.clock
libc.src.time.clock_gettime
libc.src.time.difftime
Expand Down
2 changes: 2 additions & 0 deletions libc/docs/headers/time.rst
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ Implementation Status
+---------------------+---------+---------+---------+-----------------+---------+---------+---------+---------+---------+---------+---------+---------+
| ctime_r | |check| | |check| | | |check| | | | | | | | | |
+---------------------+---------+---------+---------+-----------------+---------+---------+---------+---------+---------+---------+---------+---------+
| ctime_s | |check| | |check| | | |check| | | | | | | | | |
+---------------------+---------+---------+---------+-----------------+---------+---------+---------+---------+---------+---------+---------+---------+
| clock | |check| | |check| | | |check| | | | | | | | | |
+---------------------+---------+---------+---------+-----------------+---------+---------+---------+---------+---------+---------+---------+---------+
| clock_getcpuclockid | | | | | | | | | | | | |
Expand Down
22 changes: 22 additions & 0 deletions libc/hdr/types/errno_t.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
//===-- Proxy for errno_t -------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_HDR_TYPES_ERRNO_T_H
#define LLVM_LIBC_HDR_TYPES_ERRNO_T_H

#ifdef LIBC_FULL_BUILD

#include "include/llvm-libc-types/errno_t.h"

#else

#define __STDC_WANT_LIB_EXT1__ 1
#include <errno.h>

#endif // LIBC_FULL_BUILD

#endif // LLVM_LIBC_HDR_TYPES_ERRNO_T_H
23 changes: 23 additions & 0 deletions libc/hdr/types/rsize_t.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//===-- Proxy for rsize_t -------------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_HDR_TYPES_RSIZE_T_H
#define LLVM_LIBC_HDR_TYPES_RSIZE_T_H

#ifdef LIBC_FULL_BUILD

#include "include/llvm-libc-types/rsize_t.h"

#else

#define __need_rsize_t
#include <stddef.h>
#undef __need_rsize_t

#endif // LIBC_FULL_BUILD

#endif // LLVM_LIBC_HDR_TYPES_RSIZE_T_H
14 changes: 14 additions & 0 deletions libc/include/llvm-libc-types/errno_t.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//===-- Definition of errno_t type ----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_TYPES_ERRNO_T_H
#define LLVM_LIBC_TYPES_ERRNO_T_H

typedef int errno_t;

#endif // LLVM_LIBC_TYPES_ERRNO_T_H
16 changes: 16 additions & 0 deletions libc/include/llvm-libc-types/rsize_t.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//===-- Definition of rsize_t type ----------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_TYPES_RSIZE_T_H
#define LLVM_LIBC_TYPES_RSIZE_T_H

#include "size_t.h"

typedef size_t rsize_t;

#endif // LLVM_LIBC_TYPES_RSIZE_T_H
4 changes: 4 additions & 0 deletions libc/include/time.h.def
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@
#include "__llvm-libc-common.h"
#include "llvm-libc-macros/time-macros.h"

#ifdef __STDC_WANT_LIB_EXT1__
#include <errno.h> // errno_t
#endif

%%public_api()

#endif // LLVM_LIBC_TIME_H
9 changes: 9 additions & 0 deletions libc/include/time.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,15 @@ functions:
arguments:
- type: const time_t *
- type: char *
- name: ctime_s
standard:
- stdc
return_type: errno_t
arguments:
- type: char *
- type: rsize_t
- type: const time_t *
guard: __STDC_WANT_LIB_EXT1__
- name: clock
standard:
- stdc
Expand Down
12 changes: 12 additions & 0 deletions libc/src/time/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,18 @@ add_entrypoint_object(
libc.include.time
)

add_entrypoint_object(
ctime_s
SRCS
ctime_s.cpp
HDRS
ctime_s.h
DEPENDS
.time_utils
libc.hdr.types.time_t
libc.include.time
)

add_entrypoint_object(
difftime
SRCS
Expand Down
45 changes: 45 additions & 0 deletions libc/src/time/ctime_s.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//===-- Implementation of ctime_s function --------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#define __STDC_WANT_LIB_EXT1__ 1

#include "ctime_s.h"
#include "hdr/errno_macros.h"
#include "hdr/types/errno_t.h"
#include "hdr/types/rsize_t.h"
#include "src/__support/CPP/limits.h"
#include "src/__support/common.h"
#include "src/__support/macros/config.h"
#include "time_utils.h"

namespace LIBC_NAMESPACE_DECL {

LLVM_LIBC_FUNCTION(errno_t, ctime_s,
(char *buffer, rsize_t buffer_size, const time_t *t_ptr)) {
// TODO (https://github.com/llvm/llvm-project/issues/115907): invoke
// constraint handler
if (buffer == nullptr || t_ptr == nullptr)
return EINVAL;

if (buffer_size < time_constants::ASCTIME_MAX_BYTES ||
buffer_size > RSIZE_MAX) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm...so I went to test this with GCC and found that:

/android0/llvm-project/libc/src/time/ctime_s.cpp:30:21: error: ‘RSIZE_MAX’ was not declared in this scope; did you mean ‘SIZE_MAX’?
   30 |       buffer_size > RSIZE_MAX) {
      |                     ^~~~~~~~~
      |                     SIZE_MAX

Looking into it, I found that clang's stdint provides RSIZE_MAX (example: /usr/lib/llvm-16/lib/clang/16/include/stdint.h), but GCC does not (example: /usr/lib/gcc/x86_64-linux-gnu/14/include/stdint.h).

Grepping gcc's sources for __STDC_LIB_EXT1__ turns up no hits (one hit in the test suite that looks irrelevant). So looking into why there's seemingly no support for Annex K turned up this mailing list thread: https://gcc.gnu.org/pipermail/gcc/2019-December/231068.html

Which links to this paper documenting in explicit detail glibc developers experience with trying to implement Annex K: https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1967.htm

95f1de3 added support for RSIZE_MAX and rsize_t without mentioning who was interested in Annex K support.

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2336.pdf looks like a more recent rebuttal to n1967.

buffer[0] = '\0';
return ERANGE;
}

if (*t_ptr > cpp::numeric_limits<int32_t>::max())
return EINVAL;

if (time_utils::asctime(time_utils::localtime(t_ptr), buffer, buffer_size) ==
nullptr)
return EINVAL;

return 0;
}

} // namespace LIBC_NAMESPACE_DECL
23 changes: 23 additions & 0 deletions libc/src/time/ctime_s.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
//===-- Implementation header of ctime_s ------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_TIME_CTIME_S_H
#define LLVM_LIBC_SRC_TIME_CTIME_S_H

#include "hdr/types/errno_t.h"
#include "hdr/types/rsize_t.h"
#include "hdr/types/time_t.h"
#include "src/__support/macros/config.h"

namespace LIBC_NAMESPACE_DECL {

errno_t ctime_s(char *buffer, rsize_t buffer_size, const time_t *t_ptr);

} // namespace LIBC_NAMESPACE_DECL

#endif // LLVM_LIBC_SRC_TIME_CTIME_S_H
16 changes: 16 additions & 0 deletions libc/test/src/time/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,22 @@ add_libc_unittest(
libc.hdr.types.struct_tm
)

add_libc_unittest(
ctime_s_test
SUITE
libc_time_unittests
SRCS
ctime_s_test.cpp
HDRS
TmHelper.h
TmMatcher.h
DEPENDS
libc.include.time
libc.hdr.types.time_t
libc.src.time.ctime_s
libc.src.time.time_utils
)

add_libc_test(
clock_gettime_test
SUITE
Expand Down
67 changes: 67 additions & 0 deletions libc/test/src/time/ctime_s_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//===-- Unittests for ctime_s ---------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#define __STDC_WANT_LIB_EXT1__ 1

#include "hdr/errno_macros.h"
#include "hdr/types/errno_t.h"
#include "hdr/types/rsize_t.h"
#include "src/errno/libc_errno.h"
#include "src/time/ctime_s.h"
#include "src/time/time_utils.h"
#include "test/UnitTest/Test.h"
#include "test/src/time/TmHelper.h"

TEST(LlvmLibcCtimeS, Nullptr) {
errno_t result = LIBC_NAMESPACE::ctime_s(nullptr, 0, nullptr);
ASSERT_EQ(EINVAL, result);

char buffer[LIBC_NAMESPACE::time_constants::ASCTIME_BUFFER_SIZE];
result = LIBC_NAMESPACE::ctime_s(buffer, sizeof(buffer), nullptr);
ASSERT_EQ(EINVAL, result);

time_t t;
result = LIBC_NAMESPACE::ctime_s(nullptr, 0, &t);
ASSERT_EQ(EINVAL, result);
}

TEST(LlvmLibcCtimeS, InvalidBufferSize) {
char buffer[LIBC_NAMESPACE::time_constants::ASCTIME_BUFFER_SIZE];

time_t t = 0;
errno_t result = LIBC_NAMESPACE::ctime_s(buffer, 0, &t);
ASSERT_EQ(ERANGE, result);

result = LIBC_NAMESPACE::ctime_s(buffer, RSIZE_MAX + 1, &t);
ASSERT_EQ(ERANGE, result);
}

TEST(LlvmLibcCtimeS, ValidUnixTimestamp0) {
char buffer[LIBC_NAMESPACE::time_constants::ASCTIME_BUFFER_SIZE];
// 1970-01-01 00:00:00. Test with a valid buffer size.
time_t t = 0;
errno_t result = LIBC_NAMESPACE::ctime_s(buffer, sizeof(buffer), &t);
ASSERT_STREQ("Thu Jan 1 00:00:00 1970\n", buffer);
ASSERT_EQ(0, result);
}

TEST(LlvmLibcCtimeS, ValidUnixTimestamp32Int) {
char buffer[LIBC_NAMESPACE::time_constants::ASCTIME_BUFFER_SIZE];
// 2038-01-19 03:14:07. Test with a valid buffer size.
time_t t = 2147483647;
errno_t result = LIBC_NAMESPACE::ctime_s(buffer, sizeof(buffer), &t);
ASSERT_STREQ("Tue Jan 19 03:14:07 2038\n", buffer);
ASSERT_EQ(0, result);
}

TEST(LlvmLibcCtimeS, InvalidArgument) {
char buffer[LIBC_NAMESPACE::time_constants::ASCTIME_BUFFER_SIZE];
time_t t = 2147483648;
errno_t result = LIBC_NAMESPACE::ctime_s(buffer, sizeof(buffer), &t);
ASSERT_EQ(EINVAL, result);
}
Loading