[PATCH rtems-libbsd] ipsec-tools: Fix copying fd_set prior to select

Chris Johns chrisj at rtems.org
Tue May 23 23:13:15 UTC 2023


On 23/5/2023 5:30 pm, Christian MAUDERER wrote:
> Hello Chris,
> 
> On 2023-05-23 08:53, Chris Johns wrote:
>> On 23/5/2023 4:25 pm, Christian MAUDERER wrote:
>>> Hello Chris,
>>>
>>> On 2023-05-23 03:36, Chris Johns wrote:
>>>> Hi,
>>>>
>>>> I have been resolving this by adding:
>>>>
>>>> #define preset_mask *preset_mask_prealloc
>>>> #define active_mask *active_mask_prealloc
>>>>
>>>> as the assignment logic works as is. It does not catch FD_ZERO which is a shame
>>>> but is helps avoid us adding a special case.
>>>
>>> Thanks for the suggestion. I used that solution already in the file during the
>>> initial port. But it doesn't work in this case (and maybe we should check other
>>> cases in libbsd too). It only copies the first element of the array of fd_sets.
>>>
>>> The variables / defines are (in the patched version - see [1]):
>>>
>>> static fd_set *allocated_preset_mask, *allocated_active_mask;
>>> static struct fd_monitor *allocated_fd_monitors;
>>> #define preset_mask (*allocated_preset_mask)
>>> #define active_mask (*allocated_active_mask)
>>> #define fd_monitors (allocated_fd_monitors)
>>>
>>> They are allocated as follows (see [2]):
>>>
>>>      allocated_preset_mask = calloc(sizeof(fd_set),
>>>          howmany(rtems_libio_number_iops, sizeof(fd_set) * 8));
>>>      allocated_active_mask = calloc(sizeof(fd_set),
>>>          howmany(rtems_libio_number_iops, sizeof(fd_set) * 8));
>>>      allocated_fd_monitors = calloc(
>>>          rtems_libio_number_iops, sizeof(struct fd_monitor));
>>>
>>> So basically it's a bunch of arrays of fd_sets. If I now use the following
>>> (unpatched) assignment:
>>>
>>>      active_mask = preset_mask;
>>>
>>> After the preprocessor the line will be
>>>
>>>      (*allocated_active_mask) = (*allocated_preset_mask);
>>>
>>> Which copies only the first element. That's why I had to add the memcpy. Did I
>>> miss some better solution?
>>
>> I am using this in ntpd which I checked yesterday:
>>
>> #ifdef __rtems__
>> #include <rtems/libio_.h>
>> static size_t rtems_ntpd_fds_size;
>> static int rtems_fd_set_alloc(fd_set **setp) {
>>          if (*setp == NULL) {
>>                  rtems_ntpd_fds_size = sizeof(fd_set) *
>> (howmany(rtems_libio_number_iops, sizeof(fd_set) * 8));
>>                  *setp = malloc(rtems_ntpd_fds_size);
>>                  if (*setp == NULL) {
>>                          errno = ENOMEM;
>>                          return -1;
>>                  }
>>                  memset(*setp, 0, rtems_ntpd_fds_size);
>>          }
>>          return 0;
>> }
>> #define activefds (*activefds_prealloc)
>> static fd_set *activefds_prealloc;
>> #define rtems_activefds_alloc() rtems_fd_set_alloc(&activefds_prealloc)
>> #else /* __rtems__ */
>> static fd_set activefds;
>> #endif /* __rtems__ */
>>
>> and:
>>
>> #if __rtems__
>>          #define rdfdes (*rdfdes_prealloc)
>>          static fd_set *rdfdes_prealloc;
>> #else /* __rtems__ */
>>          fd_set rdfdes;
>> #endif /* __rtems__ */
>>          int nfound;
>>
>> #if __rtems__
>>          if (rtems_fd_set_alloc(&rdfdes_prealloc) < 0) {
>>                  return;
>>          }
>>          memset(rdfdes_prealloc, 0, rtems_ntpd_fds_size);
>> #else /* __rtems__ */
>>          FD_ZERO(&set);
>> #endif /* __rtems__ */
>>
>> with:
>>
>>          ++handler_calls;
>>          rdfdes = activefds;
> 
> But isn't that line resolving to
> 
>   (*rdfdes_prealloc) = (*activefds_prealloc);
> 
> That would also copy only the first element.
> 
>>
>> Stepping:
>>
>> Thread 9 hit Breakpoint 1, _ntp_io_handler () at
>> ../../bsd/freebsd/contrib/ntp/ntpd/ntp_io.c:3727
>> 3727            rdfdes = activefds;
>> (gdb) x /8bx activefds_prealloc
>> 0x1083e650:     0x20    0x44    0x05    0x20    0x00    0x40    0x00    0x00
>> (gdb) x /8bx rdfdes_prealloc
>> 0x108353a0:     0x00    0x00    0x00    0x00    0x00    0x00    0x00    0x00
>> (gdb) n
>> 3736                    t1.tv_usec = 0;
>> (gdb) x /8bx rdfdes_prealloc
>> 0x108353a0:     0x20    0x44    0x05    0x20    0x00    0x40    0x00    0x00
>>
>> Looks ok to me.
> 
> fd_set is 64 bit wide. So a copy of the first 64 bit works. Does it still work
> if you have 256 files in the system?

Good question. I have not checked but I will.

FYI EPICS has set its limit to 64 because of this issue with select. I suspect
they do not want to hack their select calls like this and I understand them
taking that position.

Chris


More information about the devel mailing list