diff mbox series

[v2] tools/9pfsd: Fix build error caused by strerror_r()

Message ID 20240307103847.3710737-1-xin.wang2@amd.com (mailing list archive)
State New
Headers show
Series [v2] tools/9pfsd: Fix build error caused by strerror_r() | expand

Commit Message

Henry Wang March 7, 2024, 10:38 a.m. UTC
Below error can be seen when doing Yocto build of the toolstack:

| io.c: In function 'p9_error':
| io.c:684:5: error: ignoring return value of 'strerror_r' declared
  with attribute 'warn_unused_result' [-Werror=unused-result]
|   684 |     strerror_r(err, ring->buffer, ring->ring_size);
|       |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| cc1: all warnings being treated as errors

Fix the build by using strerror() to replace strerror_r(). Since
strerror() is thread-unsafe, use a separate local mutex to protect
the action. The steps would then become: Acquire the mutex first,
invoke strerror(), copy the string from strerror() to the designated
buffer and then drop the mutex.

Signed-off-by: Henry Wang <xin.wang2@amd.com>
---
 tools/9pfsd/io.c | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

Comments

Jürgen Groß March 7, 2024, 10:51 a.m. UTC | #1
On 07.03.24 11:38, Henry Wang wrote:
> Below error can be seen when doing Yocto build of the toolstack:
> 
> | io.c: In function 'p9_error':
> | io.c:684:5: error: ignoring return value of 'strerror_r' declared
>    with attribute 'warn_unused_result' [-Werror=unused-result]
> |   684 |     strerror_r(err, ring->buffer, ring->ring_size);
> |       |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> | cc1: all warnings being treated as errors
> 
> Fix the build by using strerror() to replace strerror_r(). Since
> strerror() is thread-unsafe, use a separate local mutex to protect
> the action. The steps would then become: Acquire the mutex first,
> invoke strerror(), copy the string from strerror() to the designated
> buffer and then drop the mutex.
> 
> Signed-off-by: Henry Wang <xin.wang2@amd.com>

Maybe add a "Fixes:" tag referencing Jan's patch?

And I would expand on the reason why you are using strerror() instead of just
checking the strerror_r() result. Something like:

   Using strerror_r() without special casing different build
   environments is impossible due to the different return types
   (int vs char *) depending on the environment. As p9_error()
   is not on a performance critical path, using strerror() with a
   mutex ought to be fine.

> ---
>   tools/9pfsd/io.c | 12 +++++++++++-
>   1 file changed, 11 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/9pfsd/io.c b/tools/9pfsd/io.c
> index adb887c7d9..2b80c9528d 100644
> --- a/tools/9pfsd/io.c
> +++ b/tools/9pfsd/io.c
> @@ -680,8 +680,18 @@ static bool name_ok(const char *str)
>   static void p9_error(struct ring *ring, uint16_t tag, uint32_t err)
>   {
>       unsigned int erroff;
> +    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
> +    char *strerror_str;
> +    RING_IDX strerror_len = 0, copy_len = 0;

I wouldn't use RING_IDX for the type, but unsigned int.

> +
> +    pthread_mutex_lock(&mutex);
> +    strerror_str = strerror(err);
> +    strerror_len = strlen(strerror_str) + 1;
> +    copy_len = min(strerror_len, ring->ring_size);
> +    memcpy(ring->buffer, strerror_str, copy_len);
> +    ((char *)(ring->buffer))[copy_len - 1] = '\0';
> +    pthread_mutex_unlock(&mutex);
>   
> -    strerror_r(err, ring->buffer, ring->ring_size);
>       erroff = add_string(ring, ring->buffer, strlen(ring->buffer));
>       fill_buffer(ring, P9_CMD_ERROR, tag, "SU",
>                   erroff != ~0 ? ring->str + erroff : "cannot allocate memory",


Juergen
Jan Beulich March 7, 2024, 11:04 a.m. UTC | #2
On 07.03.2024 11:38, Henry Wang wrote:
> Below error can be seen when doing Yocto build of the toolstack:
> 
> | io.c: In function 'p9_error':
> | io.c:684:5: error: ignoring return value of 'strerror_r' declared
>   with attribute 'warn_unused_result' [-Werror=unused-result]
> |   684 |     strerror_r(err, ring->buffer, ring->ring_size);
> |       |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> | cc1: all warnings being treated as errors
> 
> Fix the build by using strerror() to replace strerror_r(). Since
> strerror() is thread-unsafe, use a separate local mutex to protect
> the action. The steps would then become: Acquire the mutex first,
> invoke strerror(), copy the string from strerror() to the designated
> buffer and then drop the mutex.
> 

Fixes: f4900d6d69b5 ("9pfsd: allow building with old glibc")

> Signed-off-by: Henry Wang <xin.wang2@amd.com>

Reviewed-by: Jan Beulich <jbeulich@suse.com>
albeit there are a number of cosmetic aspects I'd have done differently
(see bottom of mail). The one thing I'd really like to ask for it a
comment ...

> --- a/tools/9pfsd/io.c
> +++ b/tools/9pfsd/io.c
> @@ -680,8 +680,18 @@ static bool name_ok(const char *str)
>  static void p9_error(struct ring *ring, uint16_t tag, uint32_t err)
>  {
>      unsigned int erroff;
> +    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
> +    char *strerror_str;
> +    RING_IDX strerror_len = 0, copy_len = 0;
> +

... here explaining why strerror_r() isn't used. Unless other comments
arise and a v3 would be needed, I'd add

    /*
     * While strerror_r() exists, it comes in a POSIX and a GNU flavor.
     * Let's try to avoid trying to be clever with determining which
     * one it is that the underlying C library offers, when really we
     * don't expect this function to be called very often.
     */

while committing. Anyway it'll need a maintainer ack first.

> +    pthread_mutex_lock(&mutex);
> +    strerror_str = strerror(err);
> +    strerror_len = strlen(strerror_str) + 1;
> +    copy_len = min(strerror_len, ring->ring_size);
> +    memcpy(ring->buffer, strerror_str, copy_len);
> +    ((char *)(ring->buffer))[copy_len - 1] = '\0';
> +    pthread_mutex_unlock(&mutex);
>  
> -    strerror_r(err, ring->buffer, ring->ring_size);
>      erroff = add_string(ring, ring->buffer, strlen(ring->buffer));
>      fill_buffer(ring, P9_CMD_ERROR, tag, "SU",
>                  erroff != ~0 ? ring->str + erroff : "cannot allocate memory",

    pthread_mutex_lock(&mutex);
    str = strerror(err);
    len = min(strlen(str), ring->ring_size - 1);
    memcpy(ring->buffer, str, len);
    ((char *)ring->buffer)[len] = '\0';
    pthread_mutex_unlock(&mutex);

Jan
Jürgen Groß March 7, 2024, 11:24 a.m. UTC | #3
On 07.03.24 11:38, Henry Wang wrote:
> Below error can be seen when doing Yocto build of the toolstack:
> 
> | io.c: In function 'p9_error':
> | io.c:684:5: error: ignoring return value of 'strerror_r' declared
>    with attribute 'warn_unused_result' [-Werror=unused-result]
> |   684 |     strerror_r(err, ring->buffer, ring->ring_size);
> |       |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
> | cc1: all warnings being treated as errors
> 
> Fix the build by using strerror() to replace strerror_r(). Since
> strerror() is thread-unsafe, use a separate local mutex to protect
> the action. The steps would then become: Acquire the mutex first,
> invoke strerror(), copy the string from strerror() to the designated
> buffer and then drop the mutex.
> 
> Signed-off-by: Henry Wang <xin.wang2@amd.com>
> ---
>   tools/9pfsd/io.c | 12 +++++++++++-
>   1 file changed, 11 insertions(+), 1 deletion(-)
> 
> diff --git a/tools/9pfsd/io.c b/tools/9pfsd/io.c
> index adb887c7d9..2b80c9528d 100644
> --- a/tools/9pfsd/io.c
> +++ b/tools/9pfsd/io.c
> @@ -680,8 +680,18 @@ static bool name_ok(const char *str)
>   static void p9_error(struct ring *ring, uint16_t tag, uint32_t err)
>   {
>       unsigned int erroff;
> +    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
> +    char *strerror_str;
> +    RING_IDX strerror_len = 0, copy_len = 0;
> +
> +    pthread_mutex_lock(&mutex);
> +    strerror_str = strerror(err);
> +    strerror_len = strlen(strerror_str) + 1;
> +    copy_len = min(strerror_len, ring->ring_size);

Hmm, I think we even _need_ to cap the string earlier.

A string in the 9pfs protocol is a 2 byte length field plus the string.
In case of a ring larger than 65535 bytes this would mean the result of
strerror() could (in theory) overflow the string format of 9pfs.

Additionally the string should be a _short_ description of the error, so
I'd like to suggest to not use ring_size as the upper bound for the string
length, but a fixed value defined as a macro, e.g.:

#define MAX_ERRSTR_LEN 80


Juergen
Henry Wang March 7, 2024, 12:19 p.m. UTC | #4
Hi Jan,

On 3/7/2024 7:04 PM, Jan Beulich wrote:
> On 07.03.2024 11:38, Henry Wang wrote:
>> Below error can be seen when doing Yocto build of the toolstack:
>>
>> | io.c: In function 'p9_error':
>> | io.c:684:5: error: ignoring return value of 'strerror_r' declared
>>    with attribute 'warn_unused_result' [-Werror=unused-result]
>> |   684 |     strerror_r(err, ring->buffer, ring->ring_size);
>> |       |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> | cc1: all warnings being treated as errors
>>
>> Fix the build by using strerror() to replace strerror_r(). Since
>> strerror() is thread-unsafe, use a separate local mutex to protect
>> the action. The steps would then become: Acquire the mutex first,
>> invoke strerror(), copy the string from strerror() to the designated
>> buffer and then drop the mutex.
>>
>>
>> Fixes: f4900d6d69b5 ("9pfsd: allow building with old glibc")

I will add this tag in v3.
>> Signed-off-by: Henry Wang <xin.wang2@amd.com>
> Reviewed-by: Jan Beulich <jbeulich@suse.com>

Thanks!

> albeit there are a number of cosmetic aspects I'd have done differently
> (see bottom of mail). The one thing I'd really like to ask for it a
> comment ...
>
>> --- a/tools/9pfsd/io.c
>> +++ b/tools/9pfsd/io.c
>> @@ -680,8 +680,18 @@ static bool name_ok(const char *str)
>>   static void p9_error(struct ring *ring, uint16_t tag, uint32_t err)
>>   {
>>       unsigned int erroff;
>> +    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
>> +    char *strerror_str;
>> +    RING_IDX strerror_len = 0, copy_len = 0;
>> +
> ... here explaining why strerror_r() isn't used. Unless other comments
> arise and a v3 would be needed, I'd add
>
>      /*
>       * While strerror_r() exists, it comes in a POSIX and a GNU flavor.
>       * Let's try to avoid trying to be clever with determining which
>       * one it is that the underlying C library offers, when really we
>       * don't expect this function to be called very often.
>       */
>
> while committing.

Since I am working on a V3 which will be sent out soon, please don't 
bother :) I will
handle it from my side.

> Anyway it'll need a maintainer ack first.
>
>> +    pthread_mutex_lock(&mutex);
>> +    strerror_str = strerror(err);
>> +    strerror_len = strlen(strerror_str) + 1;
>> +    copy_len = min(strerror_len, ring->ring_size);
>> +    memcpy(ring->buffer, strerror_str, copy_len);
>> +    ((char *)(ring->buffer))[copy_len - 1] = '\0';
>> +    pthread_mutex_unlock(&mutex);
>>   
>> -    strerror_r(err, ring->buffer, ring->ring_size);
>>       erroff = add_string(ring, ring->buffer, strlen(ring->buffer));
>>       fill_buffer(ring, P9_CMD_ERROR, tag, "SU",
>>                   erroff != ~0 ? ring->str + erroff : "cannot allocate memory",
>      pthread_mutex_lock(&mutex);
>      str = strerror(err);
>      len = min(strlen(str), ring->ring_size - 1);

This actually will fire below errors on my build env, hence I separated 
them with a different variable.

tools/include/xen-tools/common-macros.h:38:21: error: comparison of 
distinct pointer types lacks a cast [-Werror]
|    38 |         (void) (&_x == &_y);                    \
|       |                     ^~
| io.c:695:11: note: in expansion of macro 'min'
|   695 |     len = min(strlen(str), MAX_ERRSTR_LEN - 1);;
|       |           ^~~
| cc1: all warnings being treated as errors

>      memcpy(ring->buffer, str, len);
>      ((char *)ring->buffer)[len] = '\0';
>      pthread_mutex_unlock(&mutex);

I will follow your style in V3 if you don't have any specific comment on 
the error that I posted above (plus also not strongly disagree with my 
approach in v2).

Kind regards,
Henry

> Jan
Henry Wang March 7, 2024, 12:23 p.m. UTC | #5
Hi Juergen,

On 3/7/2024 6:51 PM, Juergen Gross wrote:
> On 07.03.24 11:38, Henry Wang wrote:
>> Below error can be seen when doing Yocto build of the toolstack:
>>
>> | io.c: In function 'p9_error':
>> | io.c:684:5: error: ignoring return value of 'strerror_r' declared
>>    with attribute 'warn_unused_result' [-Werror=unused-result]
>> |   684 |     strerror_r(err, ring->buffer, ring->ring_size);
>> |       |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> | cc1: all warnings being treated as errors
>>
>> Fix the build by using strerror() to replace strerror_r(). Since
>> strerror() is thread-unsafe, use a separate local mutex to protect
>> the action. The steps would then become: Acquire the mutex first,
>> invoke strerror(), copy the string from strerror() to the designated
>> buffer and then drop the mutex.
>>
>> Signed-off-by: Henry Wang <xin.wang2@amd.com>
>
> Maybe add a "Fixes:" tag referencing Jan's patch?

Yes, will do.

> And I would expand on the reason why you are using strerror() instead 
> of just
> checking the strerror_r() result. Something like:
>
>   Using strerror_r() without special casing different build
>   environments is impossible due to the different return types
>   (int vs char *) depending on the environment. As p9_error()
>   is not on a performance critical path, using strerror() with a
>   mutex ought to be fine.

Thanks! Will add in commit message.

>> ---
>>   tools/9pfsd/io.c | 12 +++++++++++-
>>   1 file changed, 11 insertions(+), 1 deletion(-)
>>
>> diff --git a/tools/9pfsd/io.c b/tools/9pfsd/io.c
>> index adb887c7d9..2b80c9528d 100644
>> --- a/tools/9pfsd/io.c
>> +++ b/tools/9pfsd/io.c
>> @@ -680,8 +680,18 @@ static bool name_ok(const char *str)
>>   static void p9_error(struct ring *ring, uint16_t tag, uint32_t err)
>>   {
>>       unsigned int erroff;
>> +    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
>> +    char *strerror_str;
>> +    RING_IDX strerror_len = 0, copy_len = 0;
>
> I wouldn't use RING_IDX for the type, but unsigned int.

Ok, I just mainly wanted to keep some consistency, but yeah unsigned int 
is definitely ok. Will follow your suggestion.

Kind regards,
Henry
Henry Wang March 7, 2024, 12:26 p.m. UTC | #6
Hi Juergen,

On 3/7/2024 7:24 PM, Juergen Gross wrote:
> On 07.03.24 11:38, Henry Wang wrote:
>> Below error can be seen when doing Yocto build of the toolstack:
>>
>> | io.c: In function 'p9_error':
>> | io.c:684:5: error: ignoring return value of 'strerror_r' declared
>>    with attribute 'warn_unused_result' [-Werror=unused-result]
>> |   684 |     strerror_r(err, ring->buffer, ring->ring_size);
>> |       |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
>> | cc1: all warnings being treated as errors
>>
>> Fix the build by using strerror() to replace strerror_r(). Since
>> strerror() is thread-unsafe, use a separate local mutex to protect
>> the action. The steps would then become: Acquire the mutex first,
>> invoke strerror(), copy the string from strerror() to the designated
>> buffer and then drop the mutex.
>>
>> Signed-off-by: Henry Wang <xin.wang2@amd.com>
>> ---
>>   tools/9pfsd/io.c | 12 +++++++++++-
>>   1 file changed, 11 insertions(+), 1 deletion(-)
>>
>> diff --git a/tools/9pfsd/io.c b/tools/9pfsd/io.c
>> index adb887c7d9..2b80c9528d 100644
>> --- a/tools/9pfsd/io.c
>> +++ b/tools/9pfsd/io.c
>> @@ -680,8 +680,18 @@ static bool name_ok(const char *str)
>>   static void p9_error(struct ring *ring, uint16_t tag, uint32_t err)
>>   {
>>       unsigned int erroff;
>> +    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
>> +    char *strerror_str;
>> +    RING_IDX strerror_len = 0, copy_len = 0;
>> +
>> +    pthread_mutex_lock(&mutex);
>> +    strerror_str = strerror(err);
>> +    strerror_len = strlen(strerror_str) + 1;
>> +    copy_len = min(strerror_len, ring->ring_size);
>
> Hmm, I think we even _need_ to cap the string earlier.
>
> A string in the 9pfs protocol is a 2 byte length field plus the string.
> In case of a ring larger than 65535 bytes this would mean the result of
> strerror() could (in theory) overflow the string format of 9pfs.
>
> Additionally the string should be a _short_ description of the error, so
> I'd like to suggest to not use ring_size as the upper bound for the 
> string
> length, but a fixed value defined as a macro, e.g.:
>
> #define MAX_ERRSTR_LEN 80

I can use a macro-defined value in v3, sure.

Kind regards,
Henry

> Juergen
Henry Wang March 7, 2024, 12:44 p.m. UTC | #7
On 3/7/2024 8:19 PM, Henry Wang wrote:
>>      len = min(strlen(str), ring->ring_size - 1);
>
> This actually will fire below errors on my build env, hence I 
> separated them with a different variable.
>
> tools/include/xen-tools/common-macros.h:38:21: error: comparison of 
> distinct pointer types lacks a cast [-Werror]
> |    38 |         (void) (&_x == &_y); \
> |       |                     ^~
> | io.c:695:11: note: in expansion of macro 'min'
> |   695 |     len = min(strlen(str), MAX_ERRSTR_LEN - 1);;
> |       |           ^~~
> | cc1: all warnings being treated as errors
>
>>      memcpy(ring->buffer, str, len);
>>      ((char *)ring->buffer)[len] = '\0';
>>      pthread_mutex_unlock(&mutex);
>
> I will follow your style in V3 if you don't have any specific comment 
> on the error that I posted above (plus also not strongly disagree with 
> my approach in v2).

In fact I think
```
len = min(strlen(str), (size_t)(MAX_ERRSTR_LEN - 1));
```
is better.

Kind regards,
Henry

> Kind regards,
> Henry
>
>> Jan
diff mbox series

Patch

diff --git a/tools/9pfsd/io.c b/tools/9pfsd/io.c
index adb887c7d9..2b80c9528d 100644
--- a/tools/9pfsd/io.c
+++ b/tools/9pfsd/io.c
@@ -680,8 +680,18 @@  static bool name_ok(const char *str)
 static void p9_error(struct ring *ring, uint16_t tag, uint32_t err)
 {
     unsigned int erroff;
+    static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
+    char *strerror_str;
+    RING_IDX strerror_len = 0, copy_len = 0;
+
+    pthread_mutex_lock(&mutex);
+    strerror_str = strerror(err);
+    strerror_len = strlen(strerror_str) + 1;
+    copy_len = min(strerror_len, ring->ring_size);
+    memcpy(ring->buffer, strerror_str, copy_len);
+    ((char *)(ring->buffer))[copy_len - 1] = '\0';
+    pthread_mutex_unlock(&mutex);
 
-    strerror_r(err, ring->buffer, ring->ring_size);
     erroff = add_string(ring, ring->buffer, strlen(ring->buffer));
     fill_buffer(ring, P9_CMD_ERROR, tag, "SU",
                 erroff != ~0 ? ring->str + erroff : "cannot allocate memory",