Why do XS subs use const char *? - perl

A lot of Perl XS code uses const char * as the return value of an XS sub but never just char *. For example:
const char *
version(...)
CODE:
RETVAL = chromaprint_get_version();
OUTPUT: RETVAL
code from xs-fun
Can someone explain why const is preferred? In my testing, the returned scalar is modifiable whether const is used or not.

It's only for clarity. The chromaprint_get_version function returns a const char *, so the XSUB should be defined with a const char * return type as well. If you have a look at the built-in typemap, it doesn't make a difference whether you use const char *, char *, or even unsigned char *. They all use the T_PV typemap. In all cases, the XSUB will return an SV containing a copy of the C string, which is always modifiable.

Related

printf format specifiers for Perl API types

Are there macros that provide the correct printf format specifiers for IV, UV, STRLEN, Size_t and SSize_t? None are listed in perlapi.
C provides macros for the format specifiers for the types provided by stdint.h, such as uint32_t.
#include <inttypes.h>
#include <stdint.h>
uint32_t i = ...;
printf("i = %" PRIu32 "\n", i);
Is there something similar to PRIu32 for IV, UV, STRLEN, Size_t and SSize_t?
The larger problem is that I'm trying to suggest a fix for the following compilation warnings produced when installing Sort::Key on Ubuntu on Windows Subsystem for Linux:
Key.xs: In function ‘_keysort’:
Key.xs:237:12: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘IV {aka long int}’ [-Wformat=]
croak("unsupported sort type %d", type);
^~~~~~~~~~~~~~~~~~~~~~~~~~
Key.xs: In function ‘_multikeysort’:
Key.xs:547:9: warning: format ‘%d’ expects argument of type ‘int’, but argument 2 has type ‘STRLEN {aka long unsigned int}’ [-Wformat=]
croak("wrong number of results returned "
^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Key.xs:547:9: warning: format ‘%d’ expects argument of type ‘int’, but argument 3 has type ‘IV {aka long int}’ [-Wformat=]
For UV, the following macros exist:
UVuf (decimal)
UVof (octal)
UVxf (lc hex)
UVXf (uc hex)
For IV, the following macro exists:
IVdf (decimal)
For NV, the following macros exist:
NVef ("%e-ish")
NVff ("%f-ish")
NVgf ("%g-ish")
For Size_t and STRLEN, use the builtin z length modifier.[1]
%zu (decimal)
%zo (octal)
%zx (lc hex)
%zX (uc hex)
For SSize_t, use the builtin z length modifier.[1]
%zd (decimal)
For example,
IV iv = ...;
STRLEN len = ...;
croak("iv=%" IVdf " len=%zu", iv, len);
While Size_t and SSize_t are configurable, they're never different from size_t and ssize_t in practice, and STRLEN is a typedef for Size_t.
If Size_t is the same as size_t, then %zu is correct.
STRLEN is likely, but not certain, to be the same as size_t.
If SSize_t is the same as ssize_t, then %zd is probably correct (it's complicated).
For other types, if you don't know what predefined type they correspond to, convert to a known type. Knowing the signedness helps. For example:
some_unknown_signed_integer_type n = 42;
some_unknown_unsigned_integer_type x = 128;
printf("n = %jd\n", (intmax_t)n);
printf("x = %ju\n", (uintmax_t)x);
intmax_t and uintmax_t are defined in <stdint.h>.
You can get away with converting to long or unsigned long and using %ld or %lu, for example, if you happen to know that the type is no wider than long or unsigned long.

store string in char array assignment makes integer from pointer without a cast

#include <stdio.h>
int main(void){
char c[8];
*c = "hello";
printf("%s\n",*c);
return 0;
}
I am learning pointers recently. above code gives me an error - assignment makes integer from pointer without a cast [enabled by default].
I read few post on SO about this error but was not able to fix my code.
i declared c as any array of 8 char, c has address of first element. so if i do *c = "hello", it will store one char in one byte and use as many consequent bytes as needed for other characters in "hello".
Please someone help me identify the issue and help me fix it.
mark
i declared c as any array of 8 char, c has address of first element. - Yes
so if i do *c = "hello", it will store one char in one byte and use as many consequent bytes as needed for other characters in "hello". - No. Value of "hello" (pointer pointing to some static string "hello") will be assigned to *c(1byte). Value of "hello" is a pointer to string, not a string itself.
You need to use strcpy to copy an array of characters to another array of characters.
const char* hellostring = "hello";
char c[8];
*c = hellostring; //Cannot assign pointer to char
c[0] = hellostring; // Same as above
strcpy(c, hellostring); // OK
#include <stdio.h>
int main(void){
char c[8];//creating an array of char
/*
*c stores the address of index 0 i.e. c[0].
Now, the next statement (*c = "hello";)
is trying to assign a string to a char.
actually if you'll read *c as "value at c"(with index 0),
it will be more clearer to you.
to store "hello" to c, simply declare the char c[8] to char *c[8];
i.e. you have to make array of pointers
*/
*c = "hello";
printf("%s\n",*c);
return 0;
}
hope it'll help..:)

How to hash with ed25519-donna

I apologize for asking somewhat of a programming question, but I want to be sure I'm properly using this library cryptographically.
I have managed to implement ed25519-donna except for hashing the data for a signature.
As far as I can tell, this is the function that hashes data:
void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen);
but I can't figure out what *hash is. I'm fairly certain that *in and inlen are the data to be hashed and its length.
Is it something specific to SHA512?
How can one hash with ed25519-donna?
Program hangs
I've compiled with ed25519-donna-master/ed25519.o and the OpenSSL flags -lssl -lcrypto. The key generation, signing, and verification functions work as expected.
It's running without error, but the application hangs on these lines, and the cores are not running at 100%, so I don't think it's busy processing:
extern "C"
{
#include "ed25519-donna-master/ed25519.h"
#include "ed25519-donna-master/ed25519-hash.h"
}
#include <openssl/rand.h>
unsigned char* hash;
const unsigned char* in = convertStringToUnsignedCharStar( myString );
std::cout << in << std::endl;
std::cout << "this is the last portion output and 'in' outputs correctly" << std::endl;
ed25519_hash(hash, in, sizeof(in) );
std::cout << hash << std::endl;
std::cout << "this is never output" << std::endl;
How can this code be modified so that ed25519_hash can function? It works the same way regardless of whether hash and in are unsigned char* or uint8_t*s.
For uint8_t*, I used this code:
uint8_t* hash;
const uint8_t* in = reinterpret_cast<const uint8_t*>(myString.c_str());
“…but I can't figure out what *hash is.”
That uint8_t *hash is the buffer (unsigned char*) that will contain the resulting hash after you called the function.
So, you're looking at a function that expects 3 parameters (also known as arguments):
an uint8_t * buffer to hold the resulting hash,
the input data to be hashed,
the length of the input data to be hashed.
“Is it something specific to SHA512?”
Nope, it's regular C source. But I think you’re a bit confused by the documentation. It states…
If you are not compiling against OpenSSL, you will need a hash function.
…
To use a custom hash function, use -DED25519_CUSTOMHASH
when compiling ed25519.c and put your custom hash implementation
in ed25519-hash-custom.h. The hash must have a 512bit digest and
implement
…
void ed25519_hash(uint8_t *hash, const uint8_t *in, size_t inlen);
So, unless you are not compiling against OpenSSL and implementing your own hash function, you won't be needing this function. Looking at your code, you are compiling against OpenSSL, which means you're playing with the wrong function.
“How can one hash with ed25519-donna?”
By using the provided functionality the library offers.
Your question makes me wonder if you scrolled down to the “Usage” part of the readme, because it completely answers your question and tells you what functions to use.
For your convenience, let me point you to the part of the documentation you need to follow and where you find the functions you need to hash, sign, verify etc. using ed25519-donna:
To use the code, link against ed25519.o -mbits and:
#include "ed25519.h"
Add -lssl -lcrypto when using OpenSSL (Some systems don't
need -lcrypto? It might be trial and error).
To generate a private key, simply generate 32 bytes from a secure cryptographic source:
ed25519_secret_key sk;
randombytes(sk, sizeof(ed25519_secret_key));
To generate a public key:
ed25519_public_key pk;
ed25519_publickey(sk, pk);
To sign a message:
ed25519_signature sig;
ed25519_sign(message, message_len, sk, pk, signature);
To verify a signature:
int valid = ed25519_sign_open(message, message_len, pk, signature) == 0;
To batch verify signatures:
const unsigned char *mp[num] = {message1, message2..}
size_t ml[num] = {message_len1, message_len2..}
const unsigned char *pkp[num] = {pk1, pk2..}
const unsigned char *sigp[num] = {signature1, signature2..}
int valid[num]
/* valid[i] will be set to 1 if the individual signature was valid, 0 otherwise */
int all_valid = ed25519_sign_open_batch(mp, ml, pkp, sigp, num, valid) == 0;
…
As you see, it's all in there… just follow the documentation.

declaring and passing char array of different sizes correctly

I like to define a method that receives a char array of variable size.
This is my current definition:
+(int) findStartIndex: (NSData*)buffer searchPattern: (char*) searchPattern;
And this is where I call it:
const char a[] = {'a','b','c'};
startIndex = [self findStartIndex:buffer searchPattern: a];
and like this
const char b[] = {'1','2'};
startIndex = [self findStartIndex:buffer searchPattern: b];
But I keep getting the compiler warning:
Sending 'const char[3]' to parameter of type 'char *' discards qualifiers
and
Sending 'const char[2]' to parameter of type 'char *' discards qualifiers
respectively.
How to do this correctly?
Because the parameter you declared as char *, but const char [] is passed. It's a have a potential risk. you should the following changes. Do not have a warning when I tested.
+(int) findStartIndex: (NSData*)buffer searchPattern: (const char*) searchPattern
Qualifiers in C apply to the keyword on the left first, then fallback to the right next. const char arr[] is not a constant reference to a char array, it's always of type char. But, when you pass it to a method that takes a pointer to char, then you lose the const'ness of the type, and you get a warning. (Hooray for obscure C stuff!)

matlab mex: Access data

Hey there,
I don't really understand how to access data passed via arguments in matlab to a mex-function. Assuming I have the 'default' gateway function
void mexFunction( int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[] )
And now I get the pointer to the 1. input argument:
double* data_in;
data_in = mxGetPr(prhs[0]);
Both the following lines EACH seperatly make my matlab crash:
mexPrintf("%d", *data_in);
mexPrintf("%d", data_in[1]);
But why can't I access the data like that when data_in obvisously is a pointer to the first argument?
When do I need to declare the pointer as double* and when as mxArray*? Sometimes I see something like that: mxArray *arr = mxCreateDoubleMatrix(n,m,mxREAL);!?
Thanks a lot in advance!
data_in is a pointer to double so you need something like
mexPrintf("%f", data_in[0]);
This assumes the caller passed a vector or matrix of size > 0.
More generally, you can
int n = mxGetN(array);
int m = mxGetM(array);
To get the number of rows and columns of the matrix/vector passed to the mex function.
Regarding mxArray:
Matlab packs its matrices (complex and real) in an mxArray structure. mxCreateDoubleMatrix returns a pointer to such structure. To actually access that data you need to use mxGetPr() for the real part and mxGetPi() for the imaginary parts.
These return pointers to the allocated double[] arrays, which you can use to access (read and write) the elements of the matrix.
A very convenient way of handling dimensions of mxArrays is to introduce a function like the following.
#include <cstddef>
#include <cstdarg>
#include "mex.h"
bool mxCheckDimensions(const mxArray* mx_array, size_t n_dim,...) {
va_list ap; /* varargs list traverser */
size_t *dims; /* dimension list */
size_t i;
size_t dim;
bool retval = true;
va_start(ap,n_dim);
dims = (size_t *) malloc(n_dim*sizeof(size_t));
for(i=0;i<n_dim;i++) {
dims[i] = va_arg(ap,size_t);
dim = mxGetDimensions(mx_array)[i];
if (dim != dims[i])
retval = false;
}
va_end(ap);
free(dims);
return retval;
}
In this way you check an array mxArray* p is a double array of size say 1,3 using
double* pDouble = NULL;
if (mxIsDouble(p)) {
if (mxCheckDimensions(p, 2, 1, 3)) {
pDouble = (double*) GetData(p);
// Do whatever
}
}`