segmentation fault when calling c function on ruby - c

I am trying to extends my Ruby code with a C functions. The C code compiles without warning. But When I try to run the ruby code, I got a segmentation fault:
I have this c code:
#include <ruby.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "nessie.h"
/* #define TRACE_INTERMEDIATE_VALUES */
/*
* The number of rounds of the internal dedicated block cipher.
*/
#define R 10
VALUE rb_mExample;
VALUE rb_cClass;
// ...
static char* displayHash(const unsigned char array[], int length){
int i, k;
char *str;
str = malloc(3 * length + 1);
if (str == NULL) {
return NULL;
}
k = 0;
str[0] = '\0';
for (i = 0; i < length; i++){
char hex[3];
if (i % 32 == 0){
str[k++] = ' ';
}
if (i % 8 == 0){
str[k++] = ' ';
}
snprintf(hex, sizeof(hex), "%02X", array[i]);
str[k++] = hex[0];
str[k++] = hex[1];
}
str[k] = '\0';
return str;
}
VALUE
print_string(VALUE class, VALUE *valor) {
struct NESSIEstruct w;
u8 digest[DIGESTBYTES];
int i;
for (i = 0; valor[i] != '\0'; i++);
int sizeo = i;
NESSIEinit(&w);
NESSIEadd((u8*)valor, 8*sizeo, &w);
NESSIEfinalize(&w, digest);
return (VALUE) displayHash(digest, DIGESTBYTES);
}
void
Init_example(){
rb_mExample = rb_define_module("Example");
rb_cClass = rb_define_class_under(rb_mExample, "Class", rb_cObject);
rb_define_method(rb_cClass, "print_string", print_string, 1);
}
and this Ruby code:
require "example"
def print
e = Example::Class.new
e.print_string("ruby")
end
When I run the ruby code, I got a segmentation fault.
EDIT: gist with log info
https://gist.github.com/psantos10/f07484afa26ce0e55181
Where I failing? I am new in C language.
EDIT:
I changed my "print_string" to look like this:
VALUE
print_string(VALUE class, VALUE *valor) {
struct NESSIEstruct w;
u8 digest[DIGESTBYTES];
int i;
for (i = 0; valor[i] != '\0'; i++);
int sizeo = i;
NESSIEinit(&w);
NESSIEadd((u8*)valor, 8*sizeo, &w);
NESSIEfinalize(&w, digest);
return rb_str_new(displayHash(digest, DIGESTBYTES), 128);
}
whith that, segmentation fault gone. But the string returned is coming with a strange characters like:
"ruby\x00\x00\x00\x00\x00No error detected.\x00\n\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xD80x\xC0\x18`\x18\x18&F\xAF\x05#\x8C##\xB8\x91\xF9~\xC6?\xC6\xC6\xFB\xCDo\x13\xE8\x87\xE8\xE8\xCB\x13\xA1L\x87&\x87\x87\x11mb\xA9\xB8\xDA\xB8\xB8\t\x02\x05\b\x01\x04\x01\x01\r\x9EnBO!OO\x9Bl\xEE\xAD6\xD866\xFFQ\x04Y\xA6\xA2\xA6\xA6\f\xB9\xBD\xDE\xD2o\xD2"
When the correct must be only:
"ruby"
EDIT 3:
Making this change:
VALUE
print_string(VALUE class, VALUE *valor) {
struct NESSIEstruct w;
u8 digest[DIGESTBYTES];
/*
int i;
for (i = 0; valor[i] != '\0'; i++);
int sizeo = i;
*/
NESSIEinit(&w);
NESSIEadd((u8*)"ruby", 8*4, &w);
NESSIEfinalize(&w, digest);
return rb_str_new(displayHash(digest, DIGESTBYTES), 128);
}
the correct value are returned.
Then I try to to that:
VALUE
print_string(VALUE class, VALUE *valor) {
struct NESSIEstruct w;
u8 digest[DIGESTBYTES];
/*
int i;
for (i = 0; valor[i] != '\0'; i++);
int sizeo = i;
*/
NESSIEinit(&w);
NESSIEadd((u8*)"ruby", 8*4, &w);
NESSIEfinalize(&w, digest);
return rb_str_new2(valor);
}
Expecting "ruby" string to be returned. But not. It returns: "\x05"
What that mean?

for (i = 0; i < length; i++)
Inside this loop for each passing if condition you increment k so by doing this you will be having array out of bound access hence the crash.
Make sure the
char *str = malloc( 3 * length + 1);
is not
char *str = malloc( 3 * (length + 1));
For Eg:
Have value of length = 2;
char *str = malloc(7);
Now in the for loop you increment k 4 times.
k = 4;
Now after the second iteration if you exit the loop then
k=8;
So str[8] is not a valid access and might lead to crash

Before all, let me thanks #FrederickCheung for give me the right direction.
The solution code is:
VALUE
print_string(VALUE class, VALUE valor) {
struct NESSIEstruct w;
u8 digest[DIGESTBYTES];
VALUE info;
// Note here I must convert the Ruby VALUE type to C type. Thats is the trick.
char* valor2 = RSTRING_PTR(valor);
int i;
for (i = 0; valor2[i] != '\0'; i++);
int sizeo = i;
NESSIEinit(&w);
NESSIEadd((u8*)valor2, 8*sizeo, &w);
NESSIEfinalize(&w, digest);
info = rb_str_new_cstr(displayHash(digest, DIGESTBYTES));
return info;
}
For who want to see where this code was used, can access: https://github.com/AngoDev/kryptonita

Related

Returning a whole array in C

Hi I am pretty new to C and was wondering how to return an entire array. For example I have this function here.
char* foo(int x)
{
char *num = (char*)malloc(x*sizeof(int));
num[0] = '1';
num[1] = '2';
num[2] = '3';
num[3] = '4';
return num;
}
I realized that when I return num it only returns the first index of num. But is there any way to return the whole array, 1234? Any help will be greatly appreciated!
Since the foo() function returns a pointer, you can see that all values are printed when you use the %s format specifier. The display() function prints the data in the memory area pointed to by the pointer as characters.
#include <stdio.h>
#include <stdlib.h>
char* foo(int x)
{
char* num = (char*) malloc((x + 1) * sizeof(char));
for(size_t i = 0 ; i < x ; ++i)
num[i] = i + 1 + '0';
num[x] = '\0';
return num;
}
void display(char *array, size_t size)
{
for(size_t i = 0 ; i < size && array[i] != '\0' ; ++i)
printf("array[%ld]: %c\n", i, array[i]);
}
int main()
{
const size_t size = 4;
char *result = foo(size);
printf("%s\n", result);
display(result, size);
return 0;
}
Output:
1234
array[0]: 1
array[1]: 2
array[2]: 3
array[3]: 4
See if you are new to C, then learn it first do some googling and research. If you don't find anything then read some theory of a similar topic for examples (How to return an array in C?). After that some error is happening in your code then you can ask it on stackoverflow.
By the way your should be like:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *foo(int x); // fix prototype errors
char *foo(int x)
{
char *num = (char *)calloc(x + 1, sizeof(char)); // we added +1 to append the null terminating character in `num`
for (size_t i = 0; i < x; i++)
num[i] = (char)(i + 48);
return num;
}
/* #returns no. of character written on stdout */
int print_foo(const char *num); // fix prototype errors
int print_foo(const char *num)
{
if (num)
{
size_t z = 0;
for (size_t i = 0; i < num[i] != '\0'; i++)
z += fprintf(stdout, "num[%lu] = %c\n", i, num[i]);
return z;
}
return -1;
}
int main(void)
{
char *num = foo(10);
print_foo((const char *)num);
free(num); // free any heap allocated resources before exiting the application
return 0;
}

How to convert to binary as string in code C

I am trying to convert int to binary as string but I can not.
Please help me. How to convert integer to binary, please tell me.
Input: 32
Output: 00100000
My code:
#include <stdio.h>
#include <string.h>
char converttobinary(int n)
{
int i;
int a[8];
char op;
for (i = 0; i < 8; i++)
{
a[i] = n % 2;
n = (n - a[i]) / 2;
}
for (i = 7; i >= 0; i--)
{
op = strcat(op, a[i]);
}
return op;
}
int main()
{
int n;
char str;
n = 254;
str = converttobinary(n);
printf("%c", str);
return 0;
}
I have tried to modify your solution with minimal changes to make it work. There are elegant solutions to convert Integer to Binary for example using shift operators.
One of the main issue in the code was you were using character instead of character array.
i.e char str; instead of char str[SIZE];
Also you were performing string operations on a single character. Additionally, iostream header file is for C++.
There is room for lot of improvements in the solution posted below (I only made your code work with minimal changes).
My suggestion is to make your C basics strong and approach this problem again.
#include <stdio.h>
#include <string.h>
void converttobinary(int n, char *op)
{
int i;
int a[8];
for (i = 0; i < 8; i++)
{
a[i] = n % 2;
n = (n - a[i]) / 2;
}
for (i = 7; i >= 0; i--)
{
op[i]=a[i];
}
}
int main()
{
int n,i;
char str[8];
n = 8;
converttobinary(n,str);
for (i = 7; i >= 0; i--)
{
printf(" %d ",str[i]);
}
return 0;
}
char *rev(char *str)
{
char *end = str + strlen(str) - 1;
char *saved = str;
while(end > str)
{
int tmp = *str;
*str++ = *end;
*end-- = tmp;
}
return saved;
}
char *tobin(char *buff, unsigned long long data)
{
char *saved = buff;
while(data)
{
*buff++ = (data & 1) + '0';
data >>= 1;
}
*buff = 0;
return rev(saved);
}
int main()
{
char x[128];
unsigned long long z = 0x103;
printf("%llu is 0b%s\n", z, tobin(x, z));
return 0;
}
I modify your code a little bit to make what you want,
the result of this code with
n = 10
is
00001010
In this code i shift the bits n positions of the imput and compare if there is 1 or 0 in this position and write a '1' if there is a 1 or a '0' if we have a 0.
#include <stdio.h>
void converttobinary(int n, char op[8]){
int auxiliar = n;
int i;
for (i = 0; i < 8; i++) {
auxiliar = auxiliar >> i;
if (auxiliar & 1 == 1){
op[7-i] = '1';
} else{
op[7-i] = '0';
}
auxiliar = n;
}
}
int main (void){
int n = 10;
int i;
char op[8];
converttobinary(n, op);
for(i = 7; i > -1; i--){
printf("%c",op[i]);
}
return 0;
}

Counting how many times the char sir2 appears in sequence sir1[]

I've got a problem with some chars and i can't figure out how to solve it. It is given a sequence of strings and another string. And I have to count the number of appearances of the string in the sequence of strings. I did the program below but it doesn't work.
main.cpp
#include "tipulbool.h"
char sir1[25], sir2;
int n, i, k;
int main (){
cin>>n;
for(i = 1; i <= n; i++)
cin>>sir1[i];
cin>>sir2;
for(i = 1; i <= n; i++)
k += secventa(sir1[i], sir2);
cout<<k;
return 0;
}
tipulbool.h
#include <iostream>
#include <string.h>
using namespace std;
int secventa (char sir1[], char sir2);
tipulbool.cpp
#include "tipulbool.h"
int secventa (char sir1[], char sir2){
int contor;
char *p;
p = strstr(sir1[], sir2);
if(p)
contor++;
while(p){
p = strstr(p + 1, sir2);
if(p)
contor++;
}
return contor;
}
try this:
int countOfChars(char sir1[], char sir2)
{
int count = 0;
char* p = sir1;
while (*p)
{
if (p == sir2)
{
++count;
}
++p;
}
return count;
}
this code:
#include "tipulbool.h"
int secventa (char sir1[], char sir2){
int contor;
char *p;
p = strstr(sir1[], sir2);
if(p)
contor++;
while(p){
p = strstr(p + 1, sir2);
if(p)
contor++;
}
return contor;
}
gets lost in it self.
suggest:
#include "tipulbool.h"
int secventa (char sir1[], char sir2){
int contor = 0;
char *p = str1;
while(NULL != (p = strchr(p, str2) ) )
{
contor++;
p++;
}
return contor;
}
However, note that
1) I used `strchr()` rather than `strstr()`
because `str2` is a single char, not a string
2) I removed the repetitive code
3) `str1` MUST be a NULL terminated string, which in the posted code is not the case.
regarding this code:
#include "tipulbool.h"
char sir1[25], sir2;
int n, i, k;
int main (){
cin>>n;
for(i = 1; i <= n; i++)
cin>>sir1[i];
cin>>sir2;
for(i = 1; i <= n; i++)
k += secventa(sir1[i], sir2);
cout<<k;
return 0;
}
in C++, an array offset starts with 0 and continues to (length of array -1)
variables that are only used in a single function should (in general) be defined as local/auto variables within that function.
suggest using code similar to the following:
#include "tipulbool.h"
int main ( void )
{
char sir2;
int n; // will contain number of char in str1
int i; // loop counter
int k = 0; // will contain number of occurrence of str2 in str1
// get count of chars in first string
cin >> n;
// allocate room for first string (using C string)
// +1 to allow for NUL terminator byte
char *sir1 = new char[n+1];
// initialize first string
memset( sir1, 0x00, n+1 );
// input first string
for(i = 0; i < n; i++)
cin >> sir1[i];
// input target char
cin >> sir2;
// get count of occurances of str2 in str1
k = secventa(sir1, sir2);
cout << k << endl;
delete [] str1;
return 0;
}
Since this is C++, you might want to look at vector or string
to simplify the written part of the code even further

Copying custom string in C using pointers to uint64_t causes segmentation fault

As the title says, whenever I try to copy string (using my own string type and library) I get a segmentation fault. According to debugger it happens at 29th line of source (where s_strcpy4() is called), which goes to the line in sstring.h with "_dest[i] = _sour[i];". i seems to have some different value from time to time at the time of the crash, but some times sticks to one value (not sure why yet). As of the writing it got stuck at 16896.
Anyone knows where I could be causing the segfault in the code?
source.c
#include "sstring.h"
#include <string.h>
#include <stdio.h>
#include <time.h>
int main(void) {
s_string ss1,
ss2;
long long int start, end;
struct timespec time;
FILE *LoremIpsum;
s_init(&ss1, NULL, 65536);
s_init(&ss2, NULL, 65536);
LoremIpsum = fopen("Lorem ipsum", "r");
if(LoremIpsum == NULL) {
perror("Error opening file ");
return 1;
}
fgets(ss2.string, 65536, LoremIpsum);
if(fclose(LoremIpsum) == EOF) {
perror("Error closing file ");
return 2;
}
s_strcpy4(&ss1, &ss2);
return 0;
}
sstring.h
#include <stdlib.h>
#include <stdint.h>
enter code here
typedef struct {
int length;
char *string;
} s_string;
s_string *s_init(s_string *str, char *array, size_t num) {
int i;
if(str == NULL)
str = malloc(sizeof(s_string));
if(array == NULL) {
(*str).length = num;
if(num != 0)
(*str).string = malloc(num);
} else {
if(num == 0) {
(*str).string = NULL;
for(i = 0; array[i] != '\0'; i++) {
(*str).string = realloc((void *)(*str).string, i + 1);
(*str).string[i] = array[i];
}
(*str).length = i;
} else {
(*str).string = (char *)malloc(num);
(*str).length = num;
for(i = 0; i < num; i++)
(*str).string[i] = array[i];
}
}
return str;
}
s_string *s_strcpy4(s_string *__restrict__ destination, const s_string *__restrict__ source) {
int i;
long long *_dest = (long long *)(destination->string),
*_sour = (long long *)(source->string);
for(i = 0; i < source->length - 8; i+=8)
_dest[i] = _sour[i];
for( ; i < source->length; i++)
destination->string[i] = source->string[i];
destination->length = i;
return destination;
}
_dest[i] = _sour[i];
should be
_dest[i/8] = _sour[i/8];
or something equivalent.
There are lots of other things wrong with the code. For example, on architectures that require properly aligned pointers, trying to access a group of eight characters that don't start on a multiple-of-eight address will cause a bus error.
I assume you are doing this as an exercise, and not to use in production. Just use memcpy()
size_t const LLsize = sizeof(long long);
for(i = 0; i < source->length / LLsize; ++i)
_dest[i] = _sour[i];
for( i = i*LLsize; i < source->length; ++i)
destination->string[i] = source->string[i];

How to write a getline function in C?

I know that getline is C++ standard but I need to read a line of digits:
123856
and save it to an array. But how to do this without spaces between given (as input) digits? I want a user input to be:
123856 (with no spaces) and then save it to an array (n element array) and after that, I want my array to look like this:
array[0] = 1;
array[1] = 2;
array[2] = 3;
array[3] = 8;
array[4] = 5;
array[5] = 6;
But how to make it in C, without a getline?
This is NOT what I want:
#include <stdlib.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h>
int main(int argc, char **argv)
{
int t[4];
int i;
for(i=0; i<4; i++)
scanf("%d", &t[i]);
for(i=0; i<4; i++)
printf("%d\n", t[i]);
return 0;
}
If I understood you correct, the following should do it:
read the whole line
loop through the string as long as you get digits or the string ends
for every digit, place it's value in your array and increase the index by 1
while( ( c = getchar()) != EOF && c != '\n' && i < max ) {
/* If desired, add check for value outside of 0-9 */
array[ i++ ] = c - '0';
...
}
char arr[] = "1234567";
int intarr[10];
int count = 0;
for (char* ptr = arr; *ptr; ptr++) {
intarr[count] = *ptr - '0';
count++;
}
try this
#include <stdio.h>
#include <string.h>
main (int argc, char *argv[])
{
FILE *f;
int i=0;
int j=0;
char output[100];
char* output1[100];
char string[100];
char delims1[] = " ";
char delims2[] = "*";
char* result = NULL;
char* result3 = NULL;
int num;
//for (j=0; j<2; j++)
//{
//printf("%s",delims9[6]);
//}
f = fopen("text.txt","r");
//
while( fgets(string,sizeof(string),f) )
{
result = strtok( string, delims1 );
while( result != NULL )
{
output1[i]=result;
printf("%s\n",output1[i]);
result = strtok( NULL, delims1 );
i++;
}
for (num = 0; num < 100; i++ ) //
{ // Error On this array
printf("%s\n", output1[i]); //
} //
}
printf("\n%d",i/3+1);
return 0 ;
}
Ok, without using any string.
int digits = 123856;
int numofdigits = 1 + floor(log10(digits));
int digits_arr[numofdigits];
int i;
for(i = numofdigits-1; i >= 0; i--) {
digits_arr[i] = (int)floor(digits / pow(10, i)) % 10;
}
Try the below link... Same question asked here and get solution....
convert an integer number into an array
char * convertNumberIntoArray(unsigned int number) {
unsigned int length = (int)(log10((float)number)) + 1;
char * arr = (char *) malloc(length * sizeof(char)), * curr = arr;
do {
*curr++ = number % 10;
number /= 10;
} while (number != 0);
return arr;
}

Resources