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...
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).)