What does "macro annotations embedding in comments" mean in mcpp? - macros

In mcpp.exe --help
Options available with only -#std (default) option:
-#compat Expand recursive macro more than Standard.
-3 Enable trigraphs.
-K **Output macro annotations embedding in comments.**
So, what does 'macro annotation in comments' mean?
http://mcpp.sourceforge.net/

From the mcpp-summary-272.pdf file available at SourceForge (link in question):
Also
mcpp has a mode to output macro informations
embedded in comments. This mode allows you
to know macro calls and their locations on source
file from preprocessed output.
So, it leaves behind comments identifying the macros expanded, so that you can tell which source came from which macro.
Illustration
Source (x.c)
#include <assert.h>
int main(int argc, char **argv)
{
assert(argc != 0 && argv != 0);
return 0;
}
mcpp x.c
#line 1 "/Users/jleffler/src/cmd/x.c"
#line 1 "/usr/include/assert.h"
#line 42 "/usr/include/assert.h"
#line 1 "/usr/include/sys/cdefs.h"
#line 417 "/usr/include/sys/cdefs.h"
#line 1 "/usr/include/sys/_symbol_aliasing.h"
#line 418 "/usr/include/sys/cdefs.h"
#line 494 "/usr/include/sys/cdefs.h"
#line 1 "/usr/include/sys/_posix_availability.h"
#line 495 "/usr/include/sys/cdefs.h"
#line 43 "/usr/include/assert.h"
#line 61 "/usr/include/assert.h"
void abort(void) ;
int printf(const char * , ...);
#line 2 "/Users/jleffler/src/cmd/x.c"
int main(int argc, char **argv)
{
((void) ((argc != 0 && argv != 0) ? 0 : ((void)printf ("%s:%u: failed assertion `%s'\n", "/Users/jleffler/src/cmd/x.c" , 4 , "argc != 0 && argv != 0"), abort()) )) ;
return 0;
}
mccp -K x.c (excerpt)
I omitted about 560 lines of not very informative output, but the main code is:
#line 2 "/Users/jleffler/src/cmd/x.c"
int main(int argc, char **argv)
{
/*<assert 4:5-4:35*//*!assert:0-0 4:12-4:34*/((void) ((/*<assert:0-0*/argc != 0 && argv != 0/*>*/) ? 0 : /*<__assert*//*!__assert:0-0*//*!__assert:0-1*//*!__assert:0-2*/((void)printf ("%s:%u: failed assertion `%s'\n", /*<__assert:0-1*//*<__FILE__*/"/Users/jleffler/src/cmd/x.c"/*>*//*>*/, /*<__assert:0-2*//*<__LINE__*/4/*>*//*>*/, /*<__assert:0-0*//*<assert:0-0*/"argc != 0 && argv != 0"/*>*//*>*/), abort())/*>*/))/*>*/;
return 0;
}
Or, with comments isolated one per line (manually):
#line 2 "/Users/jleffler/src/cmd/x.c"
int main(int argc, char **argv)
{
/*<assert 4:5-4:35*/
/*!assert:0-0 4:12-4:34*/
((void) ((
/*<assert:0-0*/
argc != 0 && argv != 0
/*>*/
) ? 0 :
/*<__assert*/
/*!__assert:0-0*/
/*!__assert:0-1*/
/*!__assert:0-2*/
((void)printf ("%s:%u: failed assertion `%s'\n",
/*<__assert:0-1*/
/*<__FILE__*/
"/Users/jleffler/src/cmd/x.c"
/*>*/
/*>*/
,
/*<__assert:0-2*/
/*<__LINE__*/
4
/*>*/
/*>*/
,
/*<__assert:0-0*/
/*<assert:0-0*/
"argc != 0 && argv != 0"
/*>*/
/*>*/
), abort())
/*>*/
))
/*>*/
;
return 0;
}
What is the bug in this implementation of the assert() macro?
Hint: the C99 standard says:
§7.2.1.1 The assert macro
The assert macro puts diagnostic tests into programs; it expands to a void expression.
When it is executed, if expression (which shall have a scalar type) is false (that is,
compares equal to 0), the assert macro writes information about the particular call that
failed (including the text of the argument, the name of the source file, the source line
number, and the name of the enclosing function — the latter are respectively the values of
the preprocessing macros __FILE__ and __LINE__ and of the identifier
__func__) on the standard error stream in an implementation-defined format. It
then calls the abort function.
The machine is running MacOS X Lion (10.7.1).

Related

string matching in bpf programs

I am writing a bpf program in which i need to match prefix of filename in openat syscall.
Since we cannot link libc, and there is no such builtin function, i wrote one myself.
#define MAX_FILE_NAME_LENGTH 128
#define LOG_DIR "/my/prefix"
#define LEN_LOG_DIR sizeof(LOG_DIR)
int matchPrefix(char str[MAX_FILE_NAME_LENGTH]) {
for (int i = 0; i < LEN_LOG_DIR; i++) {
char ch1 = LOG_DIR[i];
if (ch1 == '\0') {
return 0;
}
char ch2 = str[i];
if (ch2 == '\0') {
return -1;
}
if (ch1 != ch2) {
return -2;
}
}
return (-3);
}
i am getting invalid mem access 'mem_or_null' error when i try to load this program.
libbpf: load bpf program failed: Permission denied
libbpf: -- BEGIN DUMP LOG ---
libbpf:
Validating matchPrefix() func#1...
38: R1=mem_or_null(id=2,off=0,imm=0) R10=fp0
; int matchPrefix(char str[MAX_FILE_NAME_LENGTH]) {
38: (18) r0 = 0xffffffff ; R0_w=P4294967295
; char ch2 = str[i];
40: (71) r2 = *(u8 *)(r1 +0)
R1 invalid mem access 'mem_or_null'
processed 2 insns (limit 1000000) max_states_per_insn 0 total_states 0 peak_states 0 mark_read 0
libbpf: -- END LOG --
libbpf: failed to load program 'syscall_enter_open'
R1 is the register for first argument. which is a char array on stack. Do i need to pass length of array separately?
the function is called this way
char filename[MAX_FILE_NAME_LENGTH];
bpf_probe_read_user(filename, sizeof(filename), args->filename);
if (matchPrefix(filename) != 0) {
return 0;
}
Even if i change the function signature to accept a char * , there is some other error R1 invalid mem access 'scalar'.
Can someone help in understanding why am i getting this error in function verification?
TL;DR. Making your matchPrefix function a static inline one should work around the verifier issue.
I believe this is happening because the BPF verifier recognizes your function as a global one (vs. inlined) and therefore verifies it independently. That means it won't assume anything for the arguments. Thus, the str argument is recognized as mem_or_null and verification fails because you didn't check that pointer isn't null.
Inlining the function will work around this issue because the verifier won't see a function anymore. It will be able to preserve the inferred type of filename when verifying the code that corresponds to the body of matchPrefix.
there is easier solution using strcmp.
find in xdp-project/bpf-next
code from the same is
int strcmp(const char *cs, const char *ct)
{
unsigned char c1, c2;
while (1) {
c1 = *cs++;
c2 = *ct++;
if (c1 != c2)
return c1 < c2 ? -1 : 1;
if (!c1)
break;
}
return 0;
}
Do let me know if you still have issue.
NOTE: you cannot use #define to define string.
do reverify line
char ch1 = LOG_DIR[i];

snprintf() return value when size=0

Thanks first for your time spent here. I have a question with snprintf() when size=0, with code below:
#include <stdio.h>
#include <stdlib.h>
int main(int ac, char **av)
{
char *str;
int len;
len = snprintf(NULL, 0, "%s %d", *av, ac);
printf("this string has length %d\n", len);
if (!(str = malloc((len + 1) * sizeof(char))))
return EXIT_FAILURE;
len = snprintf(str, len + 1, "%s %d", *av, ac);
printf("%s %d\n", str, len);
free(str);
return EXIT_SUCCESS;
}
when I run:
momo#xue5:~/TestCode$ ./Test_snprintf
The result is:
this string has length 17
./Test_snprintf 1 17
What confuses me is in the code, the size to be written is 0, why displayed 17?
What did I miss?
Thanks~~
The solution can be found in the man page under Return value;
The functions snprintf() and vsnprintf() do not write more than size bytes (including the terminating null byte ('\0')). If the output was truncated due to this limit then the return value is the number of characters (excluding the terminating null byte) which would have been written to the final string if enough space had been available.
This is so that you can do exactly what you do, a "trial print" to get the correct length, then allocate the buffer dynamically to get the whole output when you snprintf again to the allocated buffer.

command line arguments segmentation fault

int main(int argc, const char * argv[]) {
int first_arg, second_arg;
if( argv[1] == NULL || argv[2] == NULL ){
printf("no arguments! ");
exit(0);
}
else{
printf("%s %s \n", argv[1], argv[2] );
sscanf (argv[1], "%d", &first_arg);
sscanf (argv[2], "%d", &second_arg);
printf("%d %d", first_arg, second_arg);
}
}
I'm trying to get int parameters. Program works with small number parameters but when I write big numbers it gives segmentation fault. I've tried to fix it with gdb, it says:
warning: `/private/var/tmp/libplatform/libplatform-24.90.1~2/libplatform.build/libsystem_platform.build/Objects-normal/x86_64/init.o': can't open to read symbols: No such file or directory.
no arguments! [Inferior 1 (process 1275) exited normally]
it works with "100 and 1", "200 and 1" but "300 and 1" gives segmentation fault. also works "1 and 1000" but "10 and 1000" gives segmentation again.
it prints only first printf in else

How to let fscanf stop reading after a new line

#include <stdio.h>
#define MAX 1000
int line_counter (FILE *file, char buf[]);
int main(int argc, char *argv[]) {
FILE *ptr_file;
char buf[MAX];
ptr_file = fopen("alice-eg.txt", "r");
if (!ptr_file) {
return 1;
}
int count = 0;
while (fscanf(ptr_file, "%s", buf) == 1) {
printf("%s", buf);
if (buf == '\n') {
return count;
}
else {
count += 1;
}
}
printf("The number of words in this line is: %d", count);
return 0;
}
I want to do something along the lines of this but I have no idea how to make it work as the buf is just a pointer to an array of letters (correct me if I'm wrong I just started with C and my understanding of pointers is still quite bad).
fscanf write the line from the file (separated by ENTER) to the buff array and so if it will read an empty line buff[0] = '\n' so that should be your condition.
Secondly:
while (fscanf(ptr_file, "%s", buf) == 1)
Is wrong since fscanf returns the number of read character and so for the line "abcd" form the file it will return 4 and your loop will stop right away instead of reading the entire file and so your condition should be:
while (fscanf(ptr_file, "%s", buf) != EOF)
since fscanf will return EOF when it will reach the end of the file

How to use fgets() to safely handle user input more than once

I'm sorry if I duplicate, but I have tried EVERYTHING, and I can't figure out why this code keeps breaking. The highest-priority goal was to make this code handle input safely, or just anything that the user can type into the console, without it breaking. However, I also need it to be able to run more than once. fgets() won't let me do that since it keeps reading '\n' somewhere and preventing me from entering input more than once when it hits the end of the do/while loop. I have tried fflushing stdin, I have tried scanf("%d *[^\n]"); and just regular scanf("%d *[^\n]");, but none of those work, and, in fact, they break the code! I used this website to try to get the "Safely handling input" code to work, but I don't completely understand what they're doing. I tried to jerry-rig (spelling?) it as best I could, but I'm not sure if I did it right. Did I miss something? I didn't think a problem this seemingly simple could be so much of a headache! >_<
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
using namespace std;
#define BUF_LEN 100
#define SPACE 32
#define SPCL_CHAR1F 33
#define SPCL_CHAR1L 47
#define SPCL_CHAR2F 58
#define SPCL_CHAR2L 64
#define SPCL_CHAR3F 91
#define SPCL_CHAR3L 96
#define NUMF 48
#define NUML 57
#define UC_CHARF 65
#define UC_CHARL 90
#define LC_CHARF 97
#define LC_CHARL 122
void main ()
{
char* buffer;
int SpcCounter=0, SpclCounter=0, NumCounter=0,LcCounter=0, UcCounter=0;
char line[BUF_LEN],response[4];
char*input="";
bool repeat=false;
do
{
for(int i=0;i<BUF_LEN;i++)
{
line[i]=NULL;
}
buffer=NULL;
printf("Enter your mess of characters.\n");
buffer=fgets(line,BUF_LEN,stdin);
//To handle going over the buffer limit: BROKEN
if(buffer!=NULL)
{
size_t last=strlen(line)-1;
if(line[last]=='\n')
line[last]='\0';
else
{
fscanf(stdin,"%c *[^\n]");
}
}
for(int i=0;i<BUF_LEN;i++)
{
char temp=buffer[i];
if(temp==SPACE||temp==255)
SpcCounter++;
else if((temp >= SPCL_CHAR1F && temp <= SPCL_CHAR1L)||/*Special characters*/
(temp >= SPCL_CHAR2F && temp <= SPCL_CHAR2L)||
(temp >= SPCL_CHAR3F && temp <= SPCL_CHAR3L))
SpclCounter++;
else if (temp >=NUMF && temp <= NUML)/*Numbers*/
NumCounter++;
else if (temp >= UC_CHARF && temp <= UC_CHARL)/*Uppercase letters*/
UcCounter++;
else if (temp >= LC_CHARF && temp <= LC_CHARL)/*Lowercase letters*/
LcCounter++;
}
printf("There were %i space%s, %i special character%s, %i number%s, and %i letter%s,\n"
"consisting of %i uppercase letter%s and %i lowercase.\n",
SpcCounter,(SpcCounter==1?"":"s"),SpclCounter,(SpclCounter==1?"":"s"), NumCounter,(NumCounter==1?"":"s"),UcCounter+LcCounter,
(UcCounter+LcCounter==1?"":"s"), UcCounter,(UcCounter==1?"":"s"), LcCounter);
printf("Would you like to do this again? (yes/no)");
input=fgets(response,4,stdin);
/*
ALL BROKEN
if(input!=NULL)
{
size_t last=strlen(response)-1;
if(response[last]=='\n')
response[last]='\0';
else
{
fscanf(stdin,"%*[^\n]");
fscanf(stdin,"%c");
}
}
*/
//To capitalize the letters
for(int i=0;i<4;i++)
{
char* temp=&response[i];
if (*temp >= LC_CHARF && *temp <= LC_CHARL)
*temp=toupper(*temp);//Capitalize it
}
//To set repeat: WORKS, BUT WEIRD
repeat=!strncmp(input,"YES",4);
}
while(repeat);
}
For safe, secure user input in C (and in C++ if I'm using C-style strings), I usually revert to an old favorite of mine, the getLine function:
// Use stdio.h and string.h for C.
#include <cstdio>
#include <cstring>
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Output prompt then get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
This function:
can output a prompt if desired.
uses fgets in a way that avoids buffer overflow.
detects end-of-file during the input.
detects if the line was too long, by detecting lack of newline at the end.
removes the newline if there.
"eats" characters until the next newline to ensure that they're not left in the input stream for the next call to this function.
It's a fairly solid piece of code that's been tested over many years and is a good solution to the problem of user input.
In terms of how you call it for the purposes in your question, I would add something very similar to what you have, but using the getLine function instead of directly calling fgets and fiddling with the results. First some headers and the same definitions:
#include <iostream>
#include <cstdlib>
#include <cctype>
#define BUF_LEN 100
#define SPACE 32
#define SPCL_CHAR1F 33
#define SPCL_CHAR1L 47
#define SPCL_CHAR2F 58
#define SPCL_CHAR2L 64
#define SPCL_CHAR3F 91
#define SPCL_CHAR3L 96
#define NUMF 48
#define NUML 57
#define UC_CHARF 65
#define UC_CHARL 90
#define LC_CHARF 97
#define LC_CHARL 122
Then the first part of main gathering a valid line (using the function) to be evaluated:
int main () {
int SpcCounter, SpclCounter, NumCounter, LcCounter, UcCounter;
char line[BUF_LEN], response[4];
bool repeat = false;
do {
SpcCounter = SpclCounter = NumCounter = LcCounter = UcCounter = 0;
// Get a line until valid.
int stat = getLine ("\nEnter a line: ", line, BUF_LEN);
while (stat != OK) {
// End of file means no more data possible.
if (stat == NO_INPUT) {
cout << "\nEnd of file reached.\n";
return 1;
}
// Only other possibility is "Too much data on line", try again.
stat = getLine ("Input too long.\nEnter a line: ", line, BUF_LEN);
}
Note that I've changed where the counters are set to zero. Your method had them accumulating values every time through the loop rather than resetting them to zero for each input line. This is followed by your own code which assigns each character to a class:
for (int i = 0; i < strlen (line); i++) {
char temp=line[i];
if(temp==SPACE||temp==255)
SpcCounter++;
else if((temp >= SPCL_CHAR1F && temp <= SPCL_CHAR1L)||
(temp >= SPCL_CHAR2F && temp <= SPCL_CHAR2L)||
(temp >= SPCL_CHAR3F && temp <= SPCL_CHAR3L))
SpclCounter++;
else if (temp >=NUMF && temp <= NUML)
NumCounter++;
else if (temp >= UC_CHARF && temp <= UC_CHARL)
UcCounter++;
else if (temp >= LC_CHARF && temp <= LC_CHARL)
LcCounter++;
}
printf("There were %i space%s, %i special character%s, "
"%i number%s, and %i letter%s,\n"
"consisting of %i uppercase letter%s and "
"%i lowercase.\n",
SpcCounter, (SpcCounter==1?"":"s"),
SpclCounter, (SpclCounter==1?"":"s"),
NumCounter, (NumCounter==1?"":"s"),
UcCounter+LcCounter, (UcCounter+LcCounter==1?"":"s"),
UcCounter, (UcCounter==1?"":"s"),
LcCounter);
Then finally, a similar way as above for asking whether user wants to continue.
// Get a line until valid yes/no, force entry initially.
*line = 'x';
while ((*line != 'y') && (*line != 'n')) {
stat = getLine ("Try another line (yes/no): ", line, BUF_LEN);
// End of file means no more data possible.
if (stat == NO_INPUT) {
cout << "\nEnd of file reached, assuming no.\n";
strcpy (line, "no");
}
// "Too much data on line" means try again.
if (stat == TOO_LONG) {
cout << "Line too long.\n";
*line = 'x';
continue;
}
// Must be okay: first char not 'y' or 'n', try again.
*line = tolower (*line);
if ((*line != 'y') && (*line != 'n'))
cout << "Line doesn't start with y/n.\n";
}
} while (*line == 'y');
}
That way, you build up your program logic based on a solid input routine (which hopefully you'll understand as a separate unit).
You could further improve the code by removing the explicit range checks and using proper character classes with cctype(), like isalpha() or isspace(). That would make it more portable (to non-ASCII systems) but I'll leave that as an exercise for later.
A sample run of the program is:
Enter a line: Hello, my name is Pax and I am 927 years old!
There were 10 spaces, 2 special characters, 3 numbers, and 30 letters,
consisting of 3 uppercase letters and 27 lowercase.
Try another line (yes/no): yes
Enter a line: Bye for now
There were 2 spaces, 0 special characters, 0 numbers, and 9 letters,
consisting of 1 uppercase letter and 8 lowercase.
Try another line (yes/no): no