From a970559bfc501ddb3f4e1086148a3ad45d4e3364 Mon Sep 17 00:00:00 2001 From: Julien Capul Date: Tue, 19 Nov 2019 12:14:36 +0100 Subject: [PATCH] Fix usage of 'getline' function from standard library (Github issue #2) when getline() is inlined by the compiler, it resorts to using and linking against the __getdelim function from the standard library. However only the getdelim function was covered by pdwfs, not the __getdelim Besides no tests were actually covering getline and getdelim...bad, very bad. --- src/c/libc.c | 6 +-- src/c/libc.h | 2 +- src/c/pdwfs.c | 9 +++-- src/c/tests/test_getline_getdelim.c | 58 +++++++++++++++++++++++++++++ src/c/tests/testsuite.c | 6 +++ 5 files changed, 73 insertions(+), 8 deletions(-) create mode 100644 src/c/tests/test_getline_getdelim.c diff --git a/src/c/libc.c b/src/c/libc.c index bc90a75..861e069 100644 --- a/src/c/libc.c +++ b/src/c/libc.c @@ -108,7 +108,7 @@ static int (*ptr_statvfs)(const char *pathname, struct statvfs *buf) = NULL; static int (*ptr_statvfs64)(const char *pathname, struct statvfs64 *buf) = NULL; static int (*ptr_fstatvfs)(int fd, struct statvfs *buf) = NULL; static int (*ptr_fstatvfs64)(int fd, struct statvfs64 *buf) = NULL; -static ssize_t (*ptr_getdelim)(char **buf, size_t *bufsiz, int delimiter, FILE *fp) = NULL; +static ssize_t (*ptr___getdelim)(char **buf, size_t *bufsiz, int delimiter, FILE *fp) = NULL; static ssize_t (*ptr_getline)(char **lineptr, size_t *n, FILE *stream) = NULL; static DIR* (*ptr_opendir)(const char* path) = NULL; static int (*ptr_feof)(FILE *stream) = NULL; @@ -488,8 +488,8 @@ int libc_fstatvfs64(int fd, struct statvfs64 *buf) { CALL_NEXT(fstatvfs64, fd, buf) } -ssize_t libc_getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp) { - CALL_NEXT(getdelim, buf, bufsiz, delimiter, fp) +ssize_t libc___getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp) { + CALL_NEXT(__getdelim, buf, bufsiz, delimiter, fp) } ssize_t libc_getline(char **buf, size_t *bufsiz, FILE *stream) { diff --git a/src/c/libc.h b/src/c/libc.h index 5721bba..7f776ca 100644 --- a/src/c/libc.h +++ b/src/c/libc.h @@ -104,7 +104,7 @@ int libc_statvfs(const char *pathname, struct statvfs *buf); int libc_statvfs64(const char *pathname, struct statvfs64 *buf); int libc_fstatvfs(int fd, struct statvfs *buf); int libc_fstatvfs64(int fd, struct statvfs64 *buf); -ssize_t libc_getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp); +ssize_t libc___getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp); ssize_t libc_getline(char **buf, size_t *bufsiz, FILE *stream); DIR* libc_opendir(const char* path); int libc_feof(FILE *stream); diff --git a/src/c/pdwfs.c b/src/c/pdwfs.c index 81137cc..45cbc26 100644 --- a/src/c/pdwfs.c +++ b/src/c/pdwfs.c @@ -1110,16 +1110,15 @@ int fstatvfs64(int fd, struct statvfs64 *buf) { NOT_IMPLEMENTED("fstatvfs64") } -ssize_t getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *stream) { - TRACE("intercepting getdelim(buf=%p, bufsiz=%p, delimiter=%d, stream=%p)\n", buf, bufsiz, delimiter, stream) +ssize_t __getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *stream) { + TRACE("intercepting __getdelim(buf=%p, bufsiz=%p, delimiter=%d, stream=%p)\n", buf, bufsiz, delimiter, stream) if STREAM_NOT_MANAGED(stream) { - return libc_getdelim(buf, bufsiz, delimiter, stream); + return libc___getdelim(buf, bufsiz, delimiter, stream); } char *ptr, *eptr; - if (*buf == NULL || *bufsiz == 0) { *bufsiz = BUFSIZ; if ((*buf = malloc(*bufsiz)) == NULL) @@ -1153,6 +1152,8 @@ ssize_t getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *stream) { } } +ssize_t getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *stream) __attribute__((alias("__getdelim"))); + ssize_t getline(char **buf, size_t *bufsiz, FILE *stream) { TRACE("intercepting getline(buf=%p, bufsiz=%p, stream=%p)\n", buf, bufsiz, stream) diff --git a/src/c/tests/test_getline_getdelim.c b/src/c/tests/test_getline_getdelim.c new file mode 100644 index 0000000..8b501b0 --- /dev/null +++ b/src/c/tests/test_getline_getdelim.c @@ -0,0 +1,58 @@ +/* +* Copyright 2019 CEA +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#define _GNU_SOURCE +#include +#include +#include "tests.h" + +int test_getline_getdelim() { + + int n = 0; + + FILE* f = fopen(TESTFILE, "w"); + CHECK_NULL(f, "fopen") + + n = fprintf(f, "Hello World !\n"); + CHECK_ERROR(n, "fprintf") + n = fprintf(f, "Hello Go !\n"); + CHECK_ERROR(n, "fprintf") + + fclose(f); + + f = fopen(TESTFILE, "r"); + CHECK_NULL(f, "fopen") + + char * line = NULL; + size_t len = 0; + ssize_t read = 0; + + read = getline(&line, &len, f); + CHECK_ERROR(read, "getline") + + assert(strncmp(line, "Hello World !\n", 14) == 0); + + read = getdelim(&line, &len, '\n', f); + CHECK_ERROR(read, "getdelim") + + assert(strncmp(line, "Hello Go !\n", 11) == 0); + + free(line); + fclose(f); + unlink(TESTFILE); + + return 0; +} diff --git a/src/c/tests/testsuite.c b/src/c/tests/testsuite.c index b6f084d..3d5fb53 100644 --- a/src/c/tests/testsuite.c +++ b/src/c/tests/testsuite.c @@ -17,6 +17,8 @@ // from libc-testsuite #include +#include +#include "tests.h" #define RUN_TEST(a) { \ extern int test_ ##a (void); \ @@ -30,6 +32,9 @@ int main() { int err=0; + // clean pre-existing test file + unlink(TESTFILE); + RUN_TEST(access); RUN_TEST(feof); RUN_TEST(fgets); @@ -38,6 +43,7 @@ int main() RUN_TEST(fputc_fgetc); RUN_TEST(ftruncate); RUN_TEST(fwrite_fread); + RUN_TEST(getline_getdelim); RUN_TEST(lseek); RUN_TEST(mkdir_rmdir); RUN_TEST(open_close);