-1

C++ 12.2.0 throws the error

error: cannot convert ‘unsigned char (*)[91]’ to ‘unsigned char**’

on the following c++11 code snippet:

unsigned char buffer[91];

// int i2d_PUBKEY(EVP_PKEY *a, unsigned char **pp);
ptrdiff_t length = i2d_PUBKEY(m_pkey, &buffer);
  • Defining unsigned char *buffer fixes the error, but leaves the array length unspecified.
  • I had assumed unsigned char buffer[91] decays into unsigned char *buffer.

Explicitely casting like i2d_PUBKEY(m_pkey, (unsigned char **)&buffer) makes the error go away, but the code segfaults then. I suppose there is something fundamental I don't understand with respect to C++ arrays.

Can someone tell me how to write the code above so it works as intended?

RF1991
  • 2,037
  • 4
  • 8
  • 17
Multisync
  • 767
  • 6
  • 25
  • Related / possible duplicated: [Why can't we use double pointer to represent two dimensional arrays?](https://stackoverflow.com/q/4470950/11082165) – Brian61354270 Aug 06 '23 at 15:17
  • 1
    I removed the C99 variable length array tag since VLAs don't exist in standard C++ and there are no C/extension VLAs in this question. – Brian61354270 Aug 06 '23 at 15:19
  • @Brian61354270, thanks. My original code uses `buffer[length]`, but I omitted this from the question for brevity. Will remove my reference to VLA from the question as well. – Multisync Aug 06 '23 at 15:21
  • What should `pp` argument point to? What does `i2d_PUBKEY` do? *If `pp` is not `NULL`, it writes the encoded data to the buffer at `*pp`, and **increments it to point after the data just written**.* – Evg Aug 06 '23 at 15:21
  • 1
    Think about the addresses and memory involved here. `unsigned char**` is a pointer to a pointer to an `unsigned char`. If you dereference such a pointer, you'd arrive at a location in memory that contains a pointer to a `unsigned char`. If you then dereference that pointer, you'd arrive at a location in memory that contains a `unsigned char`. – Brian61354270 Aug 06 '23 at 15:23
  • The dupe is irrelevant, there are no 2D arrays here. – Evg Aug 06 '23 at 15:30
  • Side note: `std::array` and `std::vector` are your friends. Forget that C-style arrays exist. – Jesper Juhl Aug 06 '23 at 15:33
  • [Minimal fix](https://godbolt.org/z/68b3vrnbc). – Evg Aug 06 '23 at 15:40
  • @Evg, thank you, got it. Seems to work. If you provide it as answer, I'm to happy to accept it. – Multisync Aug 06 '23 at 15:49

1 Answers1

0

The first thing to note is that neither of two pointers in the signature is const. This alone should warn you because the function could modify data at two different locations, but you're passing only one (unless you expect buffer itself to change, which I guess you don't). The documentation reads:

If pp is not NULL, it writes the encoded data to the buffer at *pp, and increments it to point after the data just written.

Let's introduce the second variable to be modified:

unsigned char* ptr = &buffer[0];

Now we can pass this variable to i2d_PUBKEY():

i2d_PUBKEY(/* ... */, &ptr);

This call will write data into *ptr, i.e. into buffer. ptr itself will be modified, and that's why ptr can't be passed by value and a second pointer is needed - or a reference to a pointer if i2d_PUBKEY() were a C++ function.

Demo

Evg
  • 25,259
  • 5
  • 41
  • 83