Skip to content

Commit c5b297a

Browse files
igrrdskulina
authored andcommitted
newlib: implement posix_memalign, sysconf, realpath
Closes espressif#6119 Closes espressif#7798
1 parent 8558c68 commit c5b297a

File tree

8 files changed

+275
-15
lines changed

8 files changed

+275
-15
lines changed

components/newlib/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ set(srcs
1717
"syscalls.c"
1818
"termios.c"
1919
"stdatomic.c"
20-
"time.c")
20+
"time.c"
21+
"sysconf.c"
22+
"realpath.c")
2123
set(include_dirs platform_include)
2224

2325
if(CONFIG_SPIRAM_CACHE_WORKAROUND)

components/newlib/heap.c

Lines changed: 23 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,13 @@
1-
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
2-
//
3-
// Licensed under the Apache License, Version 2.0 (the "License");
4-
// you may not use this file except in compliance with the License.
5-
// You may obtain a copy of the License at
6-
//
7-
// http://www.apache.org/licenses/LICENSE-2.0
8-
//
9-
// Unless required by applicable law or agreed to in writing, software
10-
// distributed under the License is distributed on an "AS IS" BASIS,
11-
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12-
// See the License for the specific language governing permissions and
13-
// limitations under the License.
1+
/*
2+
* SPDX-FileCopyrightText: 2015-2021 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
146

157
#include <string.h>
168
#include <stdlib.h>
179
#include <sys/reent.h>
10+
#include <errno.h>
1811
#include <malloc.h>
1912
#include "esp_heap_caps.h"
2013

@@ -81,6 +74,23 @@ void* memalign(size_t alignment, size_t n)
8174
return heap_caps_aligned_alloc(alignment, n, MALLOC_CAP_DEFAULT);
8275
}
8376

77+
int posix_memalign(void **out_ptr, size_t alignment, size_t size)
78+
{
79+
if (size == 0) {
80+
/* returning NULL for zero size is allowed, don't treat this as an error */
81+
*out_ptr = NULL;
82+
return 0;
83+
}
84+
void *result = heap_caps_aligned_alloc(alignment, size, MALLOC_CAP_DEFAULT);
85+
if (result != NULL) {
86+
/* Modify output pointer only on success */
87+
*out_ptr = result;
88+
return 0;
89+
}
90+
/* Note: error returned, not set via errno! */
91+
return ENOMEM;
92+
}
93+
8494
/* No-op function, used to force linking this file,
8595
instead of the heap implementation from newlib.
8696
*/

components/newlib/realpath.c

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <unistd.h>
8+
#include <errno.h>
9+
#include <string.h>
10+
#include <stdlib.h>
11+
#include <assert.h>
12+
#include <sys/param.h>
13+
14+
/* realpath logic:
15+
* 1. prepend CWD (/)
16+
* 2. iterate over components (search until next '/' or end of line)
17+
* - empty, skip the component
18+
* - if it is '.', skip the component
19+
* - if it is '..'
20+
* - and out_level == 0, ??? ('/..')
21+
* - otherwise, reverse-search for '/', set out_pos to that - 1, decrement out_level
22+
* - otherwise, add the component to output, increment out_level
23+
*/
24+
25+
char * realpath(const char *file_name, char *resolved_name)
26+
{
27+
char * out_path = resolved_name;
28+
if (out_path == NULL) {
29+
/* allowed as an extension, allocate memory for the output path */
30+
out_path = malloc(PATH_MAX);
31+
if (out_path == NULL) {
32+
errno = ENOMEM;
33+
return NULL;
34+
}
35+
}
36+
37+
/* canonical path starts with / */
38+
strlcpy(out_path, "/", PATH_MAX);
39+
40+
/* pointers moving over the input and output path buffers */
41+
const char* in_ptr = file_name;
42+
char* out_ptr = out_path + 1;
43+
/* number of path components in the output buffer */
44+
size_t out_depth = 0;
45+
46+
47+
while (*in_ptr) {
48+
/* "path component" is the part between two '/' path separators.
49+
* locate the next path component in the input path:
50+
*/
51+
const char* end_of_path_component = strchrnul(in_ptr, '/');
52+
size_t path_component_len = end_of_path_component - in_ptr;
53+
54+
if (path_component_len == 0 ||
55+
(path_component_len == 1 && in_ptr[0] == '.')) {
56+
/* empty path component or '.' - nothing to do */
57+
} else if (path_component_len == 2 && in_ptr[0] == '.' && in_ptr[1] == '.') {
58+
/* '..' - remove one path component from the output */
59+
if (out_depth == 0) {
60+
/* nothing to remove */
61+
} else if (out_depth == 1) {
62+
/* there is only one path component in output;
63+
* remove it, but keep the leading separator
64+
*/
65+
out_ptr = out_path + 1;
66+
*out_ptr = '\0';
67+
out_depth = 0;
68+
} else {
69+
/* remove last path component and the separator preceding it */
70+
char * prev_sep = strrchr(out_path, '/');
71+
assert(prev_sep > out_path); /* this shouldn't be the leading separator */
72+
out_ptr = prev_sep;
73+
*out_ptr = '\0';
74+
--out_depth;
75+
}
76+
} else {
77+
/* copy path component to output; +1 is for the separator */
78+
if (out_ptr - out_path + 1 + path_component_len > PATH_MAX - 1) {
79+
/* output buffer insufficient */
80+
errno = E2BIG;
81+
goto fail;
82+
} else {
83+
/* add separator if necessary */
84+
if (out_depth > 0) {
85+
*out_ptr = '/';
86+
++out_ptr;
87+
}
88+
memcpy(out_ptr, in_ptr, path_component_len);
89+
out_ptr += path_component_len;
90+
*out_ptr = '\0';
91+
++out_depth;
92+
}
93+
}
94+
/* move input pointer to separator right after this path component */
95+
in_ptr += path_component_len;
96+
if (*in_ptr != '\0') {
97+
/* move past it unless already at the end of the input string */
98+
++in_ptr;
99+
}
100+
}
101+
return out_path;
102+
103+
fail:
104+
if (resolved_name == NULL) {
105+
/* out_path was allocated, free it */
106+
free(out_path);
107+
}
108+
return NULL;
109+
}
110+
111+
char * getcwd(char *buf, size_t size)
112+
{
113+
if (buf == NULL) {
114+
return strdup("/");
115+
}
116+
strlcpy(buf, "/", size);
117+
return buf;
118+
}
119+
120+
int chdir(const char *path)
121+
{
122+
(void) path;
123+
errno = ENOSYS;
124+
return -1;
125+
}

components/newlib/sysconf.c

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#include <unistd.h>
8+
#include <errno.h>
9+
#include "sdkconfig.h"
10+
11+
#ifdef CONFIG_FREERTOS_UNICORE
12+
#define CPU_NUM 1
13+
#else
14+
#define CPU_NUM CONFIG_SOC_CPU_CORES_NUM
15+
#endif
16+
17+
long sysconf(int arg)
18+
{
19+
switch (arg) {
20+
case _SC_NPROCESSORS_CONF:
21+
case _SC_NPROCESSORS_ONLN:
22+
return CPU_NUM;
23+
default:
24+
errno = EINVAL;
25+
return -1;
26+
}
27+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
idf_component_register(SRCS
22
"test_newlib_main.c"
33
"test_stdatomic.c"
4+
"test_misc.c"
45
REQUIRES test_utils
56
PRIV_REQUIRES unity)
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2021 Espressif Systems (Shanghai) CO LTD
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
#include <assert.h>
7+
#include <stdint.h>
8+
#include <stddef.h>
9+
#include <stdbool.h>
10+
#include <stdio.h>
11+
#include <unistd.h>
12+
#include <errno.h>
13+
#include <sys/param.h>
14+
#include <stdlib.h>
15+
#include "unity.h"
16+
#include "unity_fixture.h"
17+
18+
// unity_fixture_malloc_overrides.h defines 'free' as 'unity_free',
19+
// which can only handle pointers allocated with 'unity_malloc'.
20+
// This test allocates memory via 'posix_memalign' so calling 'free'
21+
// for these pointers causes the heap guards check to fail.
22+
#undef free
23+
24+
TEST_GROUP(misc);
25+
26+
TEST_SETUP(misc)
27+
{
28+
}
29+
30+
TEST_TEAR_DOWN(misc)
31+
{
32+
}
33+
34+
TEST(misc, posix_memalign)
35+
{
36+
void* outptr;
37+
int ret;
38+
39+
ret = posix_memalign(&outptr, 4, 0);
40+
TEST_ASSERT_EQUAL_PTR(NULL, outptr);
41+
TEST_ASSERT_EQUAL_INT(ret, 0);
42+
43+
void* magic = (void*) 0xEFEFEFEF;
44+
outptr = magic;
45+
ret = posix_memalign(&outptr, 0x10000000, 64); // too big alignment - should fail on all targets
46+
TEST_ASSERT_EQUAL_INT(ret, ENOMEM);
47+
TEST_ASSERT_EQUAL_PTR(magic, outptr); // was not modified
48+
49+
outptr = magic;
50+
ret = posix_memalign(&outptr, 16, 0x10000000); // too big size - should fail on all targets
51+
TEST_ASSERT_EQUAL_INT(ret, ENOMEM);
52+
TEST_ASSERT_EQUAL_PTR(magic, outptr); // was not modified
53+
54+
outptr = magic;
55+
ret = posix_memalign(&outptr, 16, 64);
56+
TEST_ASSERT_TRUE(outptr != magic);
57+
TEST_ASSERT_NOT_NULL(outptr);
58+
TEST_ASSERT_EQUAL_INT(ret, 0);
59+
free(outptr);
60+
}
61+
62+
TEST(misc, sysconf)
63+
{
64+
TEST_ASSERT_NOT_EQUAL(-1, sysconf(_SC_NPROCESSORS_ONLN));
65+
}
66+
67+
TEST(misc, realpath)
68+
{
69+
char out[PATH_MAX];
70+
71+
TEST_ASSERT_EQUAL_STRING("/", realpath("/", out));
72+
TEST_ASSERT_EQUAL_STRING("/", realpath("//", out));
73+
TEST_ASSERT_EQUAL_STRING("/", realpath(".", out));
74+
TEST_ASSERT_EQUAL_STRING("/", realpath("./", out));
75+
TEST_ASSERT_EQUAL_STRING("/", realpath("/.", out));
76+
TEST_ASSERT_EQUAL_STRING("/", realpath("./.", out));
77+
TEST_ASSERT_EQUAL_STRING("/", realpath("..", out));
78+
TEST_ASSERT_EQUAL_STRING("/", realpath("../..", out));
79+
TEST_ASSERT_EQUAL_STRING("/a", realpath("/a/", out));
80+
TEST_ASSERT_EQUAL_STRING("/", realpath("/a/..", out));
81+
TEST_ASSERT_EQUAL_STRING("/", realpath("/a/../..", out));
82+
TEST_ASSERT_EQUAL_STRING("/c", realpath("/a/../b/../c", out));
83+
TEST_ASSERT_EQUAL_STRING("/abc/def", realpath("/abc/./def/ghi/..", out));
84+
char* out_new = realpath("/abc/./def/ghi/..", NULL);
85+
TEST_ASSERT_NOT_NULL(out_new);
86+
TEST_ASSERT_EQUAL_STRING("/abc/def", out_new);
87+
free(out_new);
88+
}
89+
90+
TEST_GROUP_RUNNER(misc)
91+
{
92+
RUN_TEST_CASE(misc, posix_memalign)
93+
RUN_TEST_CASE(misc, sysconf)
94+
RUN_TEST_CASE(misc, realpath)
95+
}

components/newlib/test_apps/main/test_newlib_main.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
static void run_all_tests(void)
55
{
66
RUN_TEST_GROUP(stdatomic);
7+
RUN_TEST_GROUP(misc);
78
}
89

910
void app_main(void)

tools/ci/check_copyright_ignore.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1421,7 +1421,6 @@ components/mqtt/host_test/mocks/include/machine/endian.h
14211421
components/mqtt/host_test/mocks/include/sys/queue.h
14221422
components/newlib/abort.c
14231423
components/newlib/assert.c
1424-
components/newlib/heap.c
14251424
components/newlib/platform_include/assert.h
14261425
components/newlib/platform_include/errno.h
14271426
components/newlib/platform_include/esp_newlib.h

0 commit comments

Comments
 (0)