-1

I am writing a simple code with readv. So find it read 1000 buffers of characters from a file with readv and end is print it but in this loop I am getting segFault

      for (int i = 0; i < 1000; i++)
      {
        iov[i].iov_base = (char *)&buffers[i];
        iov[i].iov_len = strlen(buffers[i]) + 1;
      }

is there anything wrong with the pointers I am using. the pointer code is from this https://stackoverflow.com/a/69568527/4808760

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <string.h>
#include <sys/stat.h>

#define IP_FORMAT "*.*.*.*/*,*,*,*,*,*,*,*"


int main()
{
  char *format=IP_FORMAT;
  char (*buffers)[1001]=malloc(sizeof(char[2][1001]));
  struct iovec iov[1000];
  int fd=open ("./geoip2-ipv4_csv.csv",O_RDONLY);

  for (int i = 0; i < 1000; i++)
  {
    iov[i].iov_base = (char *)&buffers[i];
    iov[i].iov_len = strlen(buffers[i]) + 1;
  }
  int valread = readv (fd, iov, 1000);
  for(int i=0;i<1000;i++)
  {
    printf ("%d: %s", i, (char *) iov[i].iov_base);
  }


  return 0;
}
user786
  • 3,502
  • 3
  • 28
  • 56
  • 1
    Your debugger will tell you more. Invest 30 minutes to learn the basics of your debugger. – Jabberwocky Nov 12 '21 at 08:12
  • 1
    `char (*buffers)[1001]=malloc(sizeof(char[2][1001]));` allocates storage for 2 1001 character buffers. Likely you want `char (*buffers)[1001]=malloc(how_many * sizeof *buffers);` where `how_many` is the number of 1001 character buffers you want to allocate for (which looks to be 1000). If you need a constant, e.g. `#define NBUFS 1000`, define one (or more). That avoids *MagicNumbers* like `1000` and `1001` and `2`, etc.. sprinkled though your code. Don't forget to `free(buffers);` whe done with the memory. – David C. Rankin Nov 12 '21 at 08:12
  • @DavidC.Rankin now its working if I have 1000 buffers but if I increase the number of buffers to readv then it prints empty space or garbage. can u please tell why is this? – user786 Nov 12 '21 at 08:38
  • if I have `char (*buffers)[1001]=malloc(sizeof(char[1500][1001]));` many buffers and characters then how many characters will be read? is it 1500x1001 characters in all buffers combined? – user786 Nov 12 '21 at 08:43
  • `(char *)&buffers[i];` should just be `buffers[i]` if `iov[i].iov_base` is `char*`. You declare buffers as a *Pointer-to-array-of* `char[1001]`. Therefore `buffers[i]` is type `char[1001]` which on access is converted to a pointer to the first character in `buffer[i]` due to [C11 Standard - 6.3.2.1(p3)](http://port70.net/~nsz/c/c11/n1570.html#6.3.2.1p3). When you take the address of `buffer[i]` the result is `char (*)[1001]` which is a *Pointer-to-array* which you then mask the incorrect type by casting to `(char*)`. There may be others, but that is a Biggie. – David C. Rankin Nov 12 '21 at 08:53
  • You cannot call `strlen()` with uninitialized strings. – the busybee Nov 12 '21 at 10:04
  • @thebusybee thanks for comment. Is this because I did not allocate with malloc later indexes of buffer at i-th index. And just allocated 2 buffers so i=0 and i=2 and ( i=3 is Null and so on is Null after 3) can u please clarify? – user786 Nov 12 '21 at 10:14
  • I don't know why I did not get any comments on my this comment `if I have char (*buffers)[1500]=malloc(sizeof(char[1500][1001])); many buffers and characters then how many characters will be read? is it 1500x1001 characters in all buffers` can any one please tell if I have 1500 buffers each with 1001 allocated chars string sized memory them how many characters should my readv should read with all buffers in iov combined. And why it's giving me garbage values if I try to increase number of buffers and each buffer char allocated areas. I am reading big file like reading all ipv4 ranges. – user786 Nov 12 '21 at 10:19
  • 1
    Well, this is not a forum, comments are not for discussions. Please [edit] your question if you add new stuff or details or sub-questions. -- Concerning `strlen()`, the given pointer shall point to a C string that necessarily needs to be delimited by a `'\0'`. If it points to random contents, `strlen()` happily runs through the memory until it finds a `'\0'`, which can be _anywhere_, including far beyond the end of the pointed object. Often you'll experience a crash. If you want to obtain the size of a buffer, it's definitely the wrong way. – the busybee Nov 12 '21 at 10:24
  • @thebusybee yes of course. On a related thing what char (*buffers)[1001] declares. is it declares 1001 buffers or is it declares any number of buffers with 1001 characters each. Can u please explain this a little. Thanks – user786 Nov 12 '21 at 10:34
  • @thebusybee I just like to know how it should be read currently I am reading char (*buffer)[1001] as buffer will be a pointers to 1000 chars each buffer. So after this declaration I can allocate each pointer characters. And with this declaration I don't have any upper limit on how many buffers can be allocated. It could be 1000 or 100000 any number of buffers.. Just placee the limit on the number of characters in each buffer that can be allocated. That's all I am trying to ask – user786 Nov 12 '21 at 10:40
  • Also with regards to above comment iov.iov_base is void pointer and I think there is nothing wrong with this statement `iov[i].iov_base = (char *)&buffers[i];` because I am casting char pointer because if I do =buffer[i] that is not correct this will give me not an address just first character which is pointed by buffer+i but =buffer+i or =(char *)&buffer[i] is same – user786 Nov 12 '21 at 10:50

1 Answers1

1

You get the segmentation fault because you access addresses outside the allocated memory.

In char (*buffers)[1001]=malloc(sizeof(char[2][1001])); you allocate an array with 2 arrays of 1001 chars each. This is commonly known as a 2D array.

But then you do iov[i].iov_len = strlen(buffers[i]) + 1; with i greater than 1. Remember, you allocated only 2 of them, so indexes from 0 to 1 are valid for accesses, and index 2 is valid for comparison.

While we are here, strlen() is not the function to obtain the size of a character buffer.

So, how to cure this mess? Well, allocate enough memory.

#define NUMBER_OF_BUFFERS 1000
#define SIZE_OF_BUFFER 1001

/* ... */

    char (*buffers)[SIZE_OF_BUFFER] = malloc(sizeof char[NUMBER_OF_BUFFERS][SIZE_OF_BUFFER]);
    if (buffer == NULL) {
        /* Handle the allocation error, the program CANNOT continue! */
    }
    struct iovec iov[NUMBER_OF_BUFFERS];

    for (int i = 0; i < NUMBER_OF_BUFFERS; i++)
    {
        iov[i].iov_base = buffers[i];
        iov[i].iov_len = SIZE_OF_BUFFER;
    }

/* ... */

EDIT:

If I declared 1000 buffers but allocated space for 1002? Then Can I use iov_base[1002]=buffer + 1002 but I declared like char (*buffers)[1000] and and allocated like =malloc(sizeof char[1002][1000] 1000 buffers declared and 1002 allocate. So when accessing buffer +1002 is valid C

Please understand, which value is the number of buffers, and which value is the size of one buffer. That's why I introduced preprocessor macros, please read the code!

  • Given, that you mean "array of characters" by "buffer":
  • By char (*buffer)[1000]; you do not declare 1000 buffers, but one pointer to zero or more buffers of size 1000 each.
  • If you allocate 1002 buffers, you can not use buffer[1002] or buffer + 1002 to read or write memory. That index is immediately after the end of the allocated space, and you are allowed to use it for comparisons only.
the busybee
  • 8,244
  • 3
  • 12
  • 29
  • If I declared 1000 buffers but allocated space for 1002? Then Can I use iov_base[1002]=buffer + 1002 but I declared like `char (*buffers)[1000]` and and allocated like =malloc(sizeof char[1002][1000] 1000 buffers declared and 1002 allocate. So when accessing buffer +1002 is valid C – user786 Nov 12 '21 at 12:28