Invalid location in Frama-c value analysis - frama-c

I am trying to analyze some program that resemble the following using the value analysis:
int main(int argc, char **argv){
char *argv0 = argv[0];
char x = argv0[1];
char y = argv0[2];
return 0;
}
After normalization and analysis the program looks like:
int main(int argc, char **argv){
int __retres;
char *argv0;
char x;
char y;
/*# assert Value: mem_access: \valid_read(argv + 0); */
argv0 = *(argv + 0);
/*# assert Value: mem_access: \valid_read(argv0 + 1); */
x = *(argv0 + 1);
/*# assert Value: mem_access: \valid_read(argv0 + 2); */
y = *(argv0 + 2);
__retres = 0;
return __retres;
}
where the status of the first two assert is 'unknown' and the status of the third one is 'invalid'. Moreover the value analysis tells me that *(argv0 + 2) is an invalid location and flags all code after it as dead.
I'd like to understand why the last assert is invalid (and not the first two) and why *(argv0 + 2) is an invalid location.
I'm using Frama-c Silicon-20161101

Thanks to anol's comment I was able to find the relevant section in the user manual of Value Analysis (http://frama-c.com/download/frama-c-value-analysis.pdf).
Here is an extract:
5.2.4 Tweaking the automatic generation of initial values (p58)
(...)
For a variable of a pointer type, there is no way for the analyzer to guess whether the pointer
should be assumed to be pointing to a single element or to be pointing at the beginning of
an array — or indeed, in the middle of an array, which would mean that it is legal to take
negative offsets of this pointer.
By default, a pointer type is assumed to point at the beginning of an array of two elements.
This number can be changed with option
-context-width.

Related

Change and wrap keyword integers without loop in C

I'm writing a program that accepts a string at the command prompt then converts each character of the string to corresponding 0-25 digit of the alphabet. Each digit is then used to encipher each character of another string the user enters after being prompted by the program. Each alphabetic character of the second string should match the order of the string of integers and the string of integers will wrap if the second string is longer. The goal of the program is the use the first string as a key to shift each character of a message (the second string).
Example (desired output):
User runs program and enters keyword: bad
User is prompted to enter string of alphabetical characters and punctuation only: Dr. Oz
Program converts keyword 'bad' into 1,0,3
Program enciphers message into Er. Ra
What I actually get is:
… T.B.S. …
I've tried many things but unfortunately I can't seem to figure out how to loop and wrap the key without looping the second message. If you run the program you will see my problem.
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int shift(char key1);
int main(int argc, string argv[]) // user enter number at cmd prompt
{
if (argv[1] == '\0')
{
printf("Usage: ./vigenere keyword\n");
return 1;
}
string key = argv[1]; // declare second arg as string
for (int i = 0, n = strlen(key); i < n; i++)
if (isdigit(key[i]) != 0 || argc != 2)
{
printf("Usage: ./vigenere keyword\n");
return 1;
}
string text = get_string("plaintext: ");
printf("ciphertext: ");
int k;
char t;
for (int j = 0, o = strlen(text); j < o; j++)
{
t = text[j];
for (int i = 0, n = strlen(key); i < n; i++)
{
k = shift(key[i]);
if (isupper(t))
{
t += k;
if (t > 'Z')
{
t -= 26;
}
}
if (islower(t))
{
t += k;
if (t > 'z')
{
t -= 26;
}
}
printf("%c", t);
}
}
printf("\n");
}
int shift(char key1)
{
int k1 = key1;
if (islower(key1))
{
k1 %= 97;
}
if (isupper(key1))
{
k1 %= 65;
}
return k1;
}
I appreciate any help and suggestions but please keep in mind the solution should match the level of coding my program suggests. There may be many advanced ways to write this program but unfortunately we are still in the beginning of this course so showing new methods (which I will definitely try to understand) may go over my head.
Here's a modified version of your code, with changes based on my comments:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int shift(char key1);
int main(int argc, string argv[]) // user enter number at cmd prompt
{
if (argc != 2 || argv[1][0] == '\0')
{
fprintf(stderr, "Usage: ./vigenere keyword\n");
return 1;
}
string key = argv[1]; // declare second arg as string
for (int i = 0, n = strlen(key); i < n; i++)
{
if (!isalpha(key[i]))
{
fprintf(stderr, "Usage: ./vigenere keyword\n");
return 1;
}
}
string text = get_string("plain text: ");
printf("ciphertext: ");
int keylen = strlen(key);
int keyidx = 0;
for (int j = 0, o = strlen(text); j < o; j++)
{
int t = text[j];
if (isupper(t))
{
int k = shift(key[keyidx++ % keylen]);
t += k;
if (t > 'Z')
t -= 26;
}
else if (islower(t))
{
int k = shift(key[keyidx++ % keylen]);
t += k;
if (t > 'z')
t -= 26;
}
printf("%c", t);
}
printf("\n");
}
int shift(char key1)
{
if (islower(key1))
key1 -= 'a';
if (isupper(key1))
key1 -= 'A';
return key1;
}
The test for exactly two arguments and for a non-empty key are moved to the top. This is slightly different from what was suggested in the comments. The error messages are printed to standard error, not standard output. I'd probably replace the second 'usage' message with a more specific error — the key may only contain alphabetic characters or thereabouts. And the errors should include argv[0] as the program name rather than hard-coding the name. The key validation loop checks that the key is all alphabetic, rather than checking that they are not digits — there are more character classes than digits and letters. The code uses keyidx and keylen to track the length of the key and the position in the key. I use single-letter variable names, but usually only for loop indexes or simple pointers (usually pointers into strings); otherwise I use short semi-mnemonic names. There are two calls to shift() so that keyidx is only incremented when the input character is a letter. There are other ways that this could be coded.
One very important change not foretold in the comments is the change of type for t — from char to int. When it is a char, if you encrypt letter z with a letter late in the alphabet (e.g. y), the value 'z' + 24 overflows the (signed) char type prevalent on Intel machines, giving a negative value (most typically; formally, the behaviour is undefined). That leads to bogus outputs. Changing to int fixes that problem. Since the value of t is promoted to int anyway when passed to printf(), there is no harm done in the printing. I used the prompt plain text: with a space so that the input and output align on the page.
I decided not to use the extra local variable k1 in shift(). I also used subtraction instead of modulus as noted in the comments.
Given the program cc59 created from cc59.c, a sample run is:
$ cc59 bad
plain text: Dr. Oz
ciphertext: Er. Ra
$ cc59 zax
plain text: Er. Ra
ciphertext: Dr. Oz
$ cc59 ablewasiereisawelba
plain text: The quick brown fox jumps over the lazy dog. Pack my box with five dozen liquor jugs. The five boxing wizards jump quickly. How vexingly quick daft zebras jump. Bright vixens jump; dozy fowl quack.
ciphertext: Tip uqius fisef fkb uvmpt zzar lpi cehq dkk. Abck nj fkx oqxy jqne zskfn ljbykr bckj. Xpw fezp coxjyk sirivuw rmml ufjckmj. Lkw nmbzrody mytdk dbqx vetzej ncep. Xvthht wtbank rydt; lgzu jzxl qvlgg.
$ cc59 azpweaiswjwsiaewpza
plain text: Tip uqius fisef fkb uvmpt zzar lpi cehq dkk. Abck nj fkx oqxy jqne zskfn ljbykr bckj. Xpw fezp coxjyk sirivuw rmml ufjckmj. Lkw nmbzrody mytdk dbqx vetzej ncep. Xvthht wtbank rydt; lgzu jzxl qvlgg.
ciphertext: The quick brown fox jumps over the lazy dog. Pack my box with five dozen liquor jugs. The five boxing wizards jump quickly. How vexingly quick daft zebras jump. Bright vixens jump; dozy fowl quack.
$
The decrypting keys were derived by matching the 'encrypting' letters in row 1 with the decrypting letters in row 2 of the data:
abcdefghijklmnopqrstuvwxyz
azyxwvutsrqponmlkjihgfedcb
With encryption and decryption, the most basic acid test for the code is that the program can decrypt its own encrypted output given the correct decrypting key and the cipher text.

Parsing char array to integer, atoi() returns squares

I'm using an android app to send values to control servos.
Code:
char inputData[4];
char buffer[3];
void loop()
{
if(Serial.available() > 3) {
for (int i = 0; i < 4; i++){
inputData[i] = Serial.read();
}
char buffer[4];
buffer[0] = inputData[1];
buffer[1] = inputData[2];
buffer[2] = inputData[3];
buffer[3] = '\0';
int angle = atoi(buffer);
Serial.write(angle);
}
}
Issue: I'm getting the values + A-F letters to address each servo - A10, A180, B30 etc. Now the trouble is turning this to an actual integer. As you can see I've declared a character array to store the integers in and as suggested in a post on the arduino forum, I added a \0 at the end of the array. Currently, the Atoi returns random characters, mostly squares and some random numbers. I've tried even assigning them to a string and then .toInt() but same issue there, mostly squares.
Any ideas?
Thanks!
Use print or println to see the number as text. write sends it as byte and Serial Monitor shows a symbol with that ASCII code.

Converting from void * to float

I have a pointer to some location in memory passed in, void *dataLoc.
Some program is transferring memory there as a bunch of unsigned chars where 0x00 is 0 and 0xFF is one.
I want to be able to pull, say, every 4th char and convert it to the float of what number is supposed to be represented. But I'm having trouble understanding how I get from a void * to an array of char[] to an array of float[].
My initial thought was to do something like
for(i=0,i<100,i++){
floatArray[i] = (float)(*((unsigned char *)dataLoc[4*i])) / 255;
}
the void * is cast to a char *.
the next 4th char is selected from the for loop
the * dereferences the char pointer, which should give me an unsigned char,
the float should change the char into a float, but a float representation of the number I want *255
I divide by 255 to get the fraction I want.
This fails, because I get the error "pointer of type 'void ' used in arithmetic
'void' is not a pointer-to-object type and beyond this, I'm not really confident that the rest of that line will work out the way I would like.
Can someone advise the proper way to handle this?
Good that you had warnings enabled.
dataLoc[4*i] occurs before (unsigned char *)dataLoc and leads to "pointer of type 'void *' used in arithmetic ..."
Cast to unsigned char * first.
Also remove extra level of *. The following is type unsigned char
((unsigned char *)dataLoc)[4*i]
Fixed:
void * dataLoc;
float floatArray[100];
// for(i=0,i<100,i++){ Use ';', not ','
for(int i=0;i<100;i++){
// Cast to `unsigned char *` before using `[]`
// * not needed here ---v
floatArray[i] = (float)( ( ((unsigned char *)dataLoc) [4*i])) / 255;
}
or
for (int i=0; i<100 ;i++) {
unsigned char value = ((unsigned char *)dataLoc)[4*i];
floatArray[i] = value / 255.0f;
}

Storing a char in a char pointer

I have a global variable that is a *char. My main function header reads as int main(int argc, char* argv[argc]){...}. These two lines of code have to remain the way they are. The first argument of my main function is a number of type *char, that I convert to a char using atoi(...);. I am basically changing the ASCII value to its corresponding character. Now I want to store this local variable character I have into the global variable that is a char pointer. I know the problem is related to allocation of memory, but I am not sure how to go about this.
My code:
char* delim;
int main(int argc, char* argv[argc])
{
char delimCharacter;
if (isdigit(*(argv[3])) == 0) delim = argv[3]; //you can pass in a character or its ascii value
else { //if the argument is a number, then the ascii value is taken
delimCharacter = atoi((argv[3]));
printf("%s\t,%c,\n", argv[3], delimCharacter);
//sprintf( delim, "%c", delimCharacter ); // a failed attempt to do this
*delim = delimCharacter;
//strncpy(delim, delimCharacter, 1); // another failed attempt to do this
}
//printf("%s\n",delim);
This yields a seg fault.
You need to verify you have got (at least) 3 arguments before you start using them.
if (argc < 4)
{
printf("Need 3 args");
exit(1);
}
Then you need to allocate some memory to put the character in.
delim = malloc(2);
// TODO: Should check the result of malloc before using it.
*delim = delimCharacter;
delim[1] = 0; // Need to NULL terminate char*
You're dereferencing an uninitialized pointer. delim never gets initialized when it goes into the else block.
char delim[] = ","; // anything really, as long as as it's one character string
...
delim[0] = delimCharacter;
In addition to your memory issue, I think you are confused about what atoi does. It parses a string representation of a number and returns the equivalent int value, e.g. "10000" => 10,000. I think that you think it will give you the ASCII value of a character, e.g. "A" =>65.
Since you have a char *, and you are (I think) assuming that it contains a single character, you could simply do this:
delimCharacter = *(argv[3]);
However, there really seems to be no need to use the intermediate step of assigning this value to a char variable at all. If the end goal is to have delim point to the char that is the delimiter, then it seems this is all you need to do:
delim = argv[3];
Not only does this remove unnecessary code, but it means you would no longer need to allocate additional memory for delim to point to.
I would also declare delim as a const char * since I assume there is no reason to change it.

Create a random string or number in Qt4

Is there any function or something like that by which I can create totally random strings or numbers?
You can create random numbers using qrand. If you need strings, you can convert the int to string. You could also check the QUuid class, which generates Universally Unique Identifiers. Those are not 'totally random', but they are unique.
int number;
int randomValue = qrand() % number;
returns a random number randomValue with 0 <= randomValue < number.
qrand() is declared in QtGlobal which is #included by many other Qt files.
int value;
QString aString = QString::number(value);
converts an integer to QString.
The following example generates alphabetic strings with capital letters from A to Z and length = len.
QString randString(int len)
{
QString str;
str.resize(len);
for (int s = 0; s < len ; ++s)
str[s] = QChar('A' + char(qrand() % ('Z' - 'A')));
return str;
}
This is not a very good method to generate random numbers within a given range. (In fact it's very very bad for most generators )
You are assuming that the low-order bits from the generator are uniformly distributed. This is not the case with most generators. In most generators the randomness occurs in the high order bits.
By using the remainder after divisions you are in effect throwing out the randomness.
You should scale using multiplication and division. Not using the modulo operator.
eg
my_numbe r= start_required + ( generator_output * range_required)/generator_maximum;
If generator_output is in [0, generator_maximum],
my_number will be in [start_required , start_required + range_required].
Use QUuid
#include <QUuid>
QString randomStr = QUuid::createUuid();
Works in Qt6
double value= QRandomGenerator::global()->bounded(0, 10);
Generate a double from 0 to 10
Here is the good answer using qrand(). The solution below uses QUuid, as already was suggested above, to generate random and unique ids (they are all hex numbers):
#include <QApplication>
#include <QDebug>
#include <QRegularExpression>
#include <QUuid>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
// random hex string generator
for (int i = 0; i < 10; i++)
{
QString str = QUuid::createUuid().toString();
str.remove(QRegularExpression("{|}|-")); // if you want only hex numbers
qDebug() << str;
}
return a.exec();
}
Output
"479a494a852747fe90efe0dc0137d059"
"2cd7e3b404b54fad9154e46c527c368a"
"84e43735eacd4b8f8d733bf642476097"
"d7e824f920874f9d8b4264212f3bd385"
"40b1c6fa89254705801caefdab5edd96"
"b7067852cf9d45ca89dd7af6ffdcdd23"
"9a2e5e6b65c54bea8fb9e7e8e1676a1a"
"981fa826073947e68adc46ddf47e311c"
"129b0ec42aed47d78be4bfe279996990"
"818035b0e83f401d8a56f34122ba7990"

Resources