getting format not a string literal even if I add %s - c

I have looked around for answer on various forums, tried various things and still getting this error:
warning: format not a string literal and no format arguments [-Wformat-security]
The compiler point to the line in the function that has the error, here's how it looks:
int print_notes(int fd, int uid, char *searchstring) {
int note_length;
char byte=0, note_buffer[100];
note_length = find_user_note(fd, uid);
if(note_length == -1) // if end of file reached
return 0; // return 0
read(fd, note_buffer, note_length); // read note data
note_buffer[note_length] = 0; // terminate the string
if(search_note(note_buffer, searchstring)) // if searchstring found
scanf("%s", note_buffer) // Got this line from an answer in the forums
printf(note_buffer); // compiler points here
return 1;
}
If you want the full code i can post it here, but its kind of long :/ don't know if that will be ok.

Its giving warning for :
printf(note_buffer);
As you are getting string being formed at runtime and trying to print it.
Use :
printf("%s",note_buffer);

Related

Processing file extensions in C

I'm developing some code in C that reads a file extension and stores it as a code in a byte together whether a text file or binary file is being processed. Later I wish to recover the file extension that is encoded in a byte.
As a test I created a loop in the main function where I can test out the function fileExtenCode(), which is in the second listing.
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#define EXLEN 9
#define EXNUM 8
typedef unsigned char BYTE;
bool fileExtenCode(char*, BYTE*, int*);
int main(void) {
char fileExten[EXLEN];
BYTE code;
int bin;
for (;;) {
printf("Type file extension: ");
scanf_s("%s", fileExten, EXLEN);
if (fileExten[0] == '.') break;
printf("%s\n", fileExten);
code = 0;
bin = 0;
bool extFound = fileExtenCode(fileExten, &code, &bin); // <== (1)
if (extFound) printf("Extension found: TRUE\n");
else printf("Extension found: FALSE\n");
printf("%s%d", "Code: ", code);
if (bin) printf(" binary file\n");
else printf(" text file\n");
printf("\n");
printf("Type code: ");
int icode;
scanf_s("%d", &icode);
code = icode;
bin = -1;
fileExtenCode(fileExten, &code, &bin); // <== (2)
printf("%s", fileExten); // <== (5)
printf("\n");
}
return 0;
}
The function that I'm trying to test is as follows:
bool fileExtenCode(char* ext, BYTE* code, int* binary) {
char *fileEx[EXNUM] = {
"jpg1", "txt0", "html0", "xml0", "exe1", "bmp1", "gif1", "png1"};
if (*binary < 0) { // <== (3)
ext = fileEx[*code]; // <== (4)
return true;
}
size_t extLen = strlen(ext);
for (BYTE i = 0; i < EXNUM; i++) {
if (strncmp(fileEx[i], ext, extLen) == 0) {
*binary = (fileEx[i][extLen] == '1') ? 1 : 0;
*code = i;
return true;
}
}
return false;
}
The idea is that you pass a string with the file extension to fileExtenCode() in statement (1) in main, and the function searched for that extension in an array, and if found returns true together with the code argument indicating the position in array of file extensions and the binary flag as 0 or 1 indicating if the file is text or binary. A '0' or '1' immediately follows file extension in the array. If the extension is not found, the function returns with false and the return values in the arguments have no meaning.
So far so good, and this part works correctly. However, in using the function in reverse to recover the file extension given the input value of code, it fails when called with statement (2) in main. In this case binary is set to -1, and then the function is called and the condition at (3) is now true and ext in (4) recovers the file extension. This is confirmed when inserting a temporary print statement immediately after (4), but this value is not returned in (5) back in main, and an old input value is instead printed.
Obviously there is a problem with pointers, but I cannot see an obvious way of fixing it. My question is how to correct this without messing up the rest of the code, which is working correctly? Note that char* ext and BYTE* code are used for both input and output, whilst int* binary is used as an input flag and returns no useful value when set to -1.
Once this problem is fixed, then it should be relatively easy to separate the binary flag from the extension when the binary flag is set to -1. Eventually I plan to have many more file extensions, but not until this is working correctly with a sample of 8.
Getting help in fixing this problem would be most appreciated.
OK, many thanks pmg, that works, except that I have to use:
strcpy_s(ext, EXLEN, fileEx[*code]);
as the Visual Studio 2022 compiler flags an error. This also solves a warning I was getting when I declared the array *fileEx[EXNUM] with the const keyword.
In my haste last night I omitted to include the statement:
if (*code >= EXNUM) return false;
immediately after (3) to trap the case when *code goes out of bounds of *fileEx[EXNUM].

mbstowcs() gives incorrect results in Windows

I am using mbstowcs() to convert a UTF-8 encoded char* string to wchar_t*, and the latter will be fed into _wfopen(). However, I always get a NULL pointer from _wfopen() and I have found the problem is from the result of mbstowcs().
I prepared the following example and used printf for debugging...
size_t out_size;
int requiredSize;
wchar_t *wc_filename;
char *utf8_filename = "C:/Users/xxxxxxxx/Desktop/\xce\xb1\xce\xb2\xce\xb3.stdf";
wchar_t *expected_output = L"C:/Users/xxxxxxxx/Desktop/αβγ.stdf";
printf("input: %s, length: %d\n", utf8_filename, strlen(utf8_filename));
printf("correct out length is %d\n", wcslen(expected_output));
// convertion start here
setlocale(LC_ALL, "C.UTF-8");
requiredSize = mbstowcs(NULL, utf8_filename, 0);
wc_filename = (wchar_t*)malloc( (requiredSize+1) * sizeof(wchar_t));
printf("requiredsize: %d\n", requiredSize);
if (!wc_filename) {
// allocation fail
free(wc_filename);
return -1;
}
out_size = mbstowcs(wc_filename, utf8_filename, requiredSize + 1);
if (out_size == (size_t)(-1)) {
// convertion fail
free(wc_filename);
return -1;
}
printf("out_size: %d, wchar name: %ls\n", out_size, wc_filename);
if (wcscmp (wc_filename, expected_output) != 0) {
printf("converted result is not correct\n");
}
free(wc_filename);
And the console output is:
input: C:/Users/xxxxxxxx/Desktop/αβγ.stdf, length: 37
correct out length is 34
requiredsize: 37
out_size: 37, wchar name: C:/Users/xxxxxxxx/Desktop/αβγ.stdf
converted result is not correct
I just don't know why expected_output and wc_filename have the same content but the length is different? What did I do wrong here?
The problem appears to be in your choice of locale name. Replacing the following:
setlocale(LC_ALL, "C.UTF-8");
with this:
setlocale(LC_ALL, "en_US.UTF-8");
fixes the issue on my system (Windows 10, MSVC, 64-bit build) – at least, the out_size and requiredSize are both 34 and the "converted result is not correct\n" message doesn't show. Using "en_GB.UTF-8" also worked.
I'm not sure if the C Standard actually defines what locale names are, but this question/answer may be helpful: Valid Locale Names.
Note: As mentioned in the comment by Mgetz, using setlocale(LC_ALL, ".UTF-8"); also works – I guess that would be the minimal and most portable locale name to use.
Second note: You can check if the setlocale call succeeded by comparing its return value to NULL. Using your original local name will give an error message if you use the following code (but not if you remove the leading "C"):
if (setlocale(LC_ALL, "C.UTF-8") == NULL) {
printf("Error setting locale!\n");
}
Universal CRT supports UTF-8, but MSVCRT.DLL is not.
When using MINGW, you need to link to UCRT.

how to print a cursor under specific word in C, like errors/warnings in gcc compiler

I am trying to print a message and put a cursor under a word or some position of this message, for example:
Error : Type incompatibility, line:column 25:6, in a=b;
^
I've tried to do so using two printf function, if we use the same example i gave, it looks like this:
printf("Error : Type incompatibility, line:column 25:6, in a=b;");
printf(" ^");
note : the spaces in the second printf are tabulations.
but when i try it it show the cursor in the begin as it omitted the tabulations.
i replaced the tabulations by typed tabulations (\t) and it shift correctly but i have to test every-time the required number of tabulations in function of my string length.
i there any way (a method/a funtion) to do it for any string length without testing every time ?
thanks in advance.
What about something like:
void point_cursor(char* error_string, char* expression)
{
char* cursor_ptr = strstr(error_string, expression);
int spaces = cursor_ptr - error_string;
printf("%s\n", error_string);
for (int i = 0; i < spaces; i++)
{
printf(" ");
}
printf("^\n");
}
Then you call it like:
char* error = "Error : Type incompatibility, line:column 25:6, in a=b;";
char* expr = "a=b";
point_cursor(error, expr);
Output would be:
Error : Type incompatibility, line:column 25:6, in a=b;
^

Tainted string in C

I'm running Coverity tool in my file operation function and getting the following error.
As you can see below, I'm using an snprintf() before passing this variable in question to the line number shown in the error message. I guess that some sanitization of the string has to be done as a part of that snprintf(). But still the warning is shown.
Error:TAINTED_STRING (TAINTED string "fn" was passed to a tainted string sink content.) [coverity]
char fn[100]; int id = 0;
char* id_str = getenv("ID");
if (id_str) {
id = atoi(id_str);
}
memset(fn, '\0', sizeof(fn));
snprintf(fn, 100, LOG_FILE, id);
if(fn[100-1] != '\0') {
fn[100-1] = '\0';
}
log_fp = fopen (fn, "a");
Any help would be highly appreciated.
Try the following:
char* id_str = getenv("ID");
if (id_str) {
id_str = strdup(id_str);
id = atoi(id_str);
free( id_str );
}
The fn string passed to fopen is tainted by an environment variable. Using strdup may act as "sanitizing".
Error:TAINTED_STRING is warning that (as far as Coverity can tell) some aspect of the behaviour is influenced by some external input and that the external input is not examined for 'safeness' before it influences execution.
In this particular example it would appear that Coverity is wrong because the value of LOG_FILE is "/log/test%d.log" and is used with an int in the snprintf, meaning that the content of char fn[100] is always well defined.
So a reasonable course of action would be to mark the error as a non-issue so that it is ignored on future runs.
Coverity wants to make sure you sanitize any string which is coming from outside of your program, be it getenv, argv, or from some file read.
You may have a function to sanitize the input(Tainted string) and have a comment provided by Coverty which tells Coverty that input string is sanitized and the SA warning will go away.
// coverity[ +tainted_string_sanitize_content : arg-0 ]
int sanitize_mystring(char* s)
{
// Do some string validation
if validated()
return SUCCESS;
else
return FAILED;
}
// coverity[ +tainted_string_sanitize_content : arg-0 ] is the line Coverty is looking
Hope this helps.

Splitting a comma-delimited string of integers

My background is not in C (it's in Real Studio - similar to VB) and I'm really struggling to split a comma-delimited string since I'm not used to low-level string handling.
I'm sending strings to an Arduino over serial. These strings are commands in a certain format. For instance:
#20,2000,5!
#10,423,0!
'#' is the header indicating a new command and '!' is the terminating footer marking the end of a command. The first integer after '#' is the command id and the remaining integers are data (the number of integers passed as data may be anywhere from 0 - 10 integers).
I've written a sketch that gets the command (stripped of the '#' and '!') and calls a function called handleCommand() when there is a command to handle. The problem is, I really don't know how to split this command up to handle it!
Here's the sketch code:
String command; // a string to hold the incoming command
boolean commandReceived = false; // whether the command has been received in full
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
// main loop
handleCommand();
}
void serialEvent(){
while (Serial.available()) {
// all we do is construct the incoming command to be handled in the main loop
// get the incoming byte from the serial stream
char incomingByte = (char)Serial.read();
if (incomingByte == '!')
{
// marks the end of a command
commandReceived = true;
return;
}
else if (incomingByte == '#')
{
// marks the start of a new command
command = "";
commandReceived = false;
return;
}
else
{
command += incomingByte;
return;
}
}
}
void handleCommand() {
if (!commandReceived) return; // no command to handle
// variables to hold the command id and the command data
int id;
int data[9];
// NOT SURE WHAT TO DO HERE!!
// flag that we've handled the command
commandReceived = false;
}
Say my PC sends the Arduino the string "#20,2000,5!". My sketch ends up with a String variable (called command) that contains "20,2000,5" and the commandRecieved boolean variable is set to True so the handleCommand() function is called.
What I would like to do in the (currently useless) handleCommand() function is assign 20 to a variable called id and 2000 and 5 to an array of integers called data, i.e: data[0] = 2000, data[1] = 5, etc.
I've read about strtok() and atoi() but frankly I just can't get my head around them and the concept of pointers. I'm sure my Arduino sketch could be optimised too.
Since you're using the Arduino core String type, strtok and other string.h functions aren't appropriate. Note that you can change your code to use standard C null-terminated strings instead, but using Arduino String will let you do this without using pointers.
The String type gives you indexOf and substring.
Assuming a String with the # and ! stripped off, finding your command and arguments would look something like this:
// given: String command
int data[MAX_ARGS];
int numArgs = 0;
int beginIdx = 0;
int idx = command.indexOf(",");
String arg;
char charBuffer[16];
while (idx != -1)
{
arg = command.substring(beginIdx, idx);
arg.toCharArray(charBuffer, 16);
// add error handling for atoi:
data[numArgs++] = atoi(charBuffer);
beginIdx = idx + 1;
idx = command.indexOf(",", beginIdx);
}
data[numArgs++] = command.substring(beginIdx);
This will give you your entire command in the data array, including the command number at data[0], while you've specified that only the args should be in data. But the necessary changes are minor.
seems to work, could be buggy:
#include<stdio.h>
#include <string.h>
int main(){
char string[]="20,2000,5";
int a,b,c;
sscanf(string,"%i,%i,%i",&a,&b,&c);
printf("%i %i %i\n",a,b,c);
a=b=c=0;
a=atoi(strtok(string,","));
b=atoi(strtok(0,","));
c=atoi(strtok(0,","));
printf("%i %i %i\n",a,b,c);
return 0;
}

Resources