Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

warning: format string contains '\0' within the string body [-Wformat]

I've got a system() command inside my code which uses awk. I can't figure out how to fix an issue with\x00 hexadecimal values. Apparently they need to be terminated differently, but that's beyond the realm of what I know.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char *argv[]) {

    char command[128];
    snprintf(command, sizeof(command), "awk '{ gsub (/\xAB\x00\x00\xBC/,\"\xBC\x00\x00\xAB\") ; print }' %s", argv[1]);
    system(command);

}

Warnings/Errors:

>  test.c:8:56: warning: format string contains '\0' within the string body [-Wformat]
>  snprintf(command, sizeof(command), "awk '{ gsub (/\xAB\x00\xBC/,\"\xBC\x00\x00\xAB\") ; print }' %s", argv[1]);
>  /usr/include/secure/_stdio.h:57:62: note: expanded from macro 'snprintf'
>  __builtin___snprintf_chk (str, len, 0, __darwin_obsz(str), __VA_ARGS__)
                                                              ^
  1 warning generated.
  sh: -c: line 0: unexpected EOF while looking for matching `''
  sh: -c: line 1: syntax error: unexpected end of file

Sorry if this has been asked before, I couldn't find any relevant info though in the search on how to fix this, thanks...

like image 544
Jack O'Leary Avatar asked Mar 13 '23 11:03

Jack O'Leary


2 Answers

Consider the C string literal "\xAB". This string literal contains one byte, not 4. Similarly, "\x00" is a string literal that contains one byte which is a null byte. Clang warns you about that because a null byte ends the C string — every character after it will be ignored by library functions such as snprintf.

In your awk code, there's an awk string literal, surrounded by double quotes. You wrote …\"\xBC\x00\x00\xAB\"…, with backslashes in front of the double quotes, because otherwise the double quotes would be interpreted as ending the C string literal. Similarly, if you want to end up with a backslash in the awk code (more precisely, in the shell command), you need another backslash in front of it. In other words, you need to double your backslashes.

snprintf(command, sizeof(command), "awk '{ gsub (/\\xAB\\x00\\x00\\xBC/,\"\\xBC\\x00\\x00\\xAB\") ; print }' %s", argv[1]);

Beware that there's another quoting problem with your program: it interprets its argument as a snippet of shell code, not as a file name. The two only coincide if the file name doesn't contain any shell special characters. For example, ./your_program Jack.txt will work, but not ./your_program "O'Leary.txt". To make it work, you need to massage the argument to protect shell special characters.

(Another problem is that you don't check whether snprintf succeeds. It could overflow — you should dynamically allocate the necessary size based on the length of the argument (don't forget to account for the extra quoting if the argument contains special characters).)

like image 121
Gilles 'SO- stop being evil' Avatar answered Apr 28 '23 03:04

Gilles 'SO- stop being evil'


The sequence of characters '\', 'x', '0', '0' within a C string literal represents a single char with numeric value zero. Thus, the char arrays represented by the two string literals "\x00" and "\0" have the same size and contents: two chars (including the terminator), both zero. When used as C strings, both are equivalent to an empty string because the zero character at index zero serves as a string terminator.

Your compiler is warning you that the string literal you pass to snprintf() contains internal null bytes (it has two, in fact), which likely will lead to it not being interpreted as you intended. If you mean the \xhh sequences in the string to be taken as sequences of four literal characters, then you must double the backslashes:

    snprintf(command, sizeof(command), "awk '{ gsub (/\\xAB\\x00\\x00\\xBC/,\"\\xBC\\x00\\x00\\xAB\") ; print }' %s", argv[1]);
like image 31
John Bollinger Avatar answered Apr 28 '23 01:04

John Bollinger