I am programming a game of connect four server and client, and I need to transmit the game array to the client via a string.
I am trying to collect the array in a string variable, playerBoard, using strcat, but it seems that when it gets to the client, it displays garbage, and also, the server is showing me Segmentation fault as an error
Server:
else
{
bzero(playersBoard, 100);
int k, j;
for( k = 0; k < HEIGTH; k++ )
{
for( j=0; j < WIDTH; j++ )
{
strcat(playersBoard, (char *)gameArray[k][j]);
strcat(playersBoard, " ");
}
}
strcat(playersBoard, "Now is your turn");
printf("Players board is : \n%s\n", playersBoard);
if(write(tdL.cl, playersBoard, 100) <= 0)
{
printf("[thread %d]\n", tdL.idThread);
perror("[thread] Error at write\n");
}
else
printf("[thread %d] Message was sent with success\n", tdL.idThread);
goto playerOneRetry;
}
Client:
if (write (sd, message, sizeof(message)) <= 0)
{
perror ("[client]Eroare la write() spre server.\n");
return errno;
}
char message2[100];
fflush(stdout);
if (read (sd, message2, 100 ) < 0)
{
perror ("[client]Eroare la read() de la server.\n");
return errno;
}
//writing message
printf ("[client]Message received is : %s\n", message2);
(char *)gameArray[k][j]
1e : (char *)gameArray[k][j] : why the cast ? gameArray[k][j] should be a 2 dim. array of type (char *). If you need to make the cast you probably defined it wrong which would cause the seg. fault.
2e : are you sure you don't overrun playersBoard ? That would cause it.
3e : bzero(playersBoard, 100); : the size of playersBoard is probably known. You should always try to avoid the static 100 and replace it by maybe : sizeof(playerBoard).
4e : You can prevent overrun of playersBoard. Using strncat and don't write more than you can. In the line of defensive programming .. you should.
The expression gameArray[k][j] is a single character, it's not a string. You can not use it as argument in strcat. Trying to cast the character to char * will turn the encoded character into a pointer which is not going to point to a valid string. Using it as such will lead to undefined behavior.
You can append a single character to a string like e.g.
playersBoard[strlen(playersBoard)] = gameArray[k][j];
playersBoard[strlen(playersBoard) + 1] = '\0';
You should really keep an eye on the warnings the compiler will emit, and without the cast it should have said something. Warnings are often a sing of you doing something you should not be doing, and disabling them is usually not a good idea as it only hides the symptom and not the problem.
Also be careful with casting, in most situations it's considered a code smell. If you find you need to cast something then you probably are doing something wrong as well.
The combination of warnings and casting is the worst of all, as like I said above you only hide the problem, but don't solve it.
Related
I am trying to execute a program with the execvp function within an overseer and client distributed system. The client sends a program to be executed with the arguments:
char buf[500];
int bytes_recieved = 0;
char array[1][26];
bytes_recieved = recv(clientfd, buf, 5000, 0);
buf[bytes_recieved] = '\0';
char buf1[50];
int bytes_recieved1 = 0;
char *array1[4];
for (int i = 0; i < 3; i++){
bytes_recieved1 = recv(clientfd, buf1, 50, 0);
array1[i] = buf1;
printf("%s = buffer\n", buf1);
}
buf1[bytes_recieved] = '\0';
if(bytes_recieved != -1){
printTime();
fprintf(stdout,"atempting to execute program: %s\n", buf);
if(execvp(buf, array1) == -1) {
return 1;
}
}
I'm stuck on trying to figure out what happens when I print out the array of arguments in the program the last argument is the same for all of them? for example I run this in the client program to be executed:
./client 12345 home/user/test_program 1 2 3
the result from a simple printf is:
3
3
3
When I manually assign each argument in the array in the overseer:
array1[0] = "1";
array1[1] = "2";
array1[2] = "3";
and send it to the executed program it prints correctly.
I have also tested that the received buffer from the file descriptor is correctly assigning the variables in the array:
printf("%s = buffer\n", array1[i]);
within the assignment for loop, which returns:
1 = buffer
2 = buffer
3 = buffer
What am I doing wrong?
Let me know if you need any more information.
This is some skeletal code, based on your code fragment. I can't test it — you did not provide an MCVE (Minimal, Complete, Verifiable Example
— or MRE or whatever name SO now uses)
or an
SSCCE (Short, Self-Contained, Correct Example).
char buf[500];
int bytes_received = recv(clientfd, buf, sizeof(buf)-1, 0);
if (bytes_received < 0)
return 1;
buf[bytes_received] = '\0';
char *array1[5] = { buf };
for (int i = 0; i < 3; i++)
{
char buf1[50];
int bytes_received1 = recv(clientfd, buf1, sizeof(buf1)-1, 0);
if (bytes_received1 < 0)
return 1;
buf1[bytes_received1] = '\0';
array1[i + 1] = strdup(buf1);
printf("argument = [%s]\n", buf1);
}
printTime();
printf("atempting to execute program: %s\n", buf);
for (int i = 0; array1[i] != NULL; i++)
printf("argv[%d] = [%s]\n", i, array1[i]);
fflush(0);
execvp(array1[0], array1);
fprintf(stderr, "failed to execute '%s'\n", array1[0]);
return 1;
Multiple changes include:
Using sizeof to determine array sizes.
Changing spelling of "receive".
Subtracting 1 to allow space for a terminal null byte to convert messages to strings.
Making array1 big enough to hold a terminal NULL pointer and initializing (indirectly) the elements after the zeroth to NULL. This is important; the argument array to execvp() must be terminated with a NULL pointer.
Return if the initial receive fails, to avoid indexing by a negative number.
Making the buf1 array local to the loop; ditto bytes_received1.
Return if a subsequent receive fails, to avoid indexing by a negative number.
Making a copy of the strings read using strdup() — this is a key change.
Not trying to null-terminate buf1 at a position based on the data received in buf.
Revising the printing, putting square brackets around the string so trailing spaces or newlines can be spotted more easily.
Printing all the arguments to execvp().
Debating whether the debug output should go to stderr instead of stdout. I ended up leaving it going to stdout, but that isn't necessarily the best choice.
Changing one fprintf(stdout, …) to printf(…) for consistency.
Calling fflush(0) to send any pending output to its devices. With the debugging output going to stdout, if the output is piped to another program, the data will be fully buffered, not line buffered, and won't appear unless you force it to. Calling fflush(stdout) would also be an option. It's probable that you shouldn't (don't) have any file streams other than stdin, stdout, stderr open when you're calling execvp().
You should consider whether other streams (file descriptors) should be closed before reaching here, perhaps using the O_CLOEXEC or FC_CLOEXEC options to ensure that the file descriptors are closed on successful exec, so that the executed process doesn't get active file descriptors it doesn't know about.
Not bothering to check the return value from execvp(). If it returns, it failed; if it succeeds, it doesn't return.
Reporting an error message when execvp() fails to execute.
Leaving return 1; as part of the code after the failed execvp(). It would often be better to use exit(EXIT_FAILURE); or similar (_exit(EXIT_FAILURE) perhaps). Without the larger context of the function that calls this fragment of a function, it isn't possible to know what's best here.
Note that if execvp() fails and returns, rather than exits, you're leaking the memory allocated by strdup(). There should probably be a loop for (int i = 0; i < 3; i++) free(array1[i+1]); to release the copied memory before the return 1;.
The code doesn't check that there was no data truncation — it doesn't know if one of the recv() calls would have read more data than it did because there wasn't enough space to store all the data. You'd probably want to check that the actual data size is smaller than the space available to ensure that there wasn't truncation.
It isn't clear why the program name can be ten times bigger than the arguments. In general, arguments can be bigger than program names, though, since your sample data has arguments like 1, 2, 3, this is not a problem.
Im using fgets to read from 2 different pipes which have been sent 2 different messages thus should be returning 2 different messages. I have 2 pipes for each and closed the unneeded child end, all my fprintfs are flushed yet theyre both returning the same message then it just hangs. I have no idea why. Debugging didnt help me though i could have missed something.
int reader(FILE *output, int **pipes, char *getMessage) {
if(output == NULL) {
fprintf(stderr, "Player quit\n");
}
fgets(getMessage, sizeof(getMessage), output);
printf("mes %s\n", getMessage);
return 0;
}
Is my reader method (I am using the same buffer for both but i was using memset to try to clear it each time:
printf("test%c\n", roundDeck[deckPos]);
fprintf(input[pickturn], "yourturn %c\n", roundDeck[deckPos]);
fprintf(stdout, "yourturn %c\n", roundDeck[deckPos]);
fflush(input[pickturn]);
allHeldCards[pickturn][1] = roundDeck[deckPos];
roundDeck[deckPos] = '-';
//fclose(inPut);
deckPos++;
if(deckPos == 16) {
deckPos = 0;
}
printf("pt %d\n", pickturn);
reader(output[pickturn], pipes, getMessage);
if(msgProcess(pickturn, allIds, allFlags, allHeldCards,
getMessage, pipes, roundDeck,
deckPos, numPlayers, input) == 1) {
roundDeck[deckPos] = '-';
deckPos++;
if(deckPos == 16) {
deckPos = 0;
}
}
memset(getMessage, 0, 50);
the inputs were changing where they needed to do on the outside so maybe Im using memset incorrectly?
There is a problem here:
fgets(getMessage, sizeof(getMessage), output);
Since getMessage has type char *, then sizeof(getMessage) is sizeof(char *) which is likely to be 4 or 8. You read that many bytes from the "output" into getMessage.
Instead, you need to specify how many bytes to read. Even if you replace sizeof(getMessage) with your buffer size, that means it will block until all that number of bytes have been read, or the input is closed. Either your message protocol has to contain the length it expects to read, or you have to define your function to read until the input is closed or a certain delimiter occurs.
Then you have to make sure that the data you read contains a null-terminated string before you try and print it with %s or any other function that expects a string.
Not clear why your inputs are called output and your outputs are called input either.
It's hard to debug further without seeing more of a complete program than just these snippets
The following is a code snippet from my read from pipe function. This executes properly and verified that the data is got into buffer .
int readFrom(char *buffer)
{
int nread;
if((nread = read(readfd,buffer,100)) < 0)
{
printf("\nerror in reading data from FIFO\n");
return(-1);
}
buffer[nread]='\0';
return(0);
}
In the above example nread is less than 100 . I am using GCC-4.7.0.
We had an abstraction layer for the above function like below :
int pipe_input(char *parmPtr, int size)
{
char readMsg[100];
if( readFrom((char *)&readMsg) == -1)
return ERROR;
if (strlen(readMsg) < 1)
{
printf("Incorrect Input\n");
return ERROR;
}
strncpy(parmPtr, readMsg, ((size < 100)?size:100));
return 0;
}
In the above function as well it was verified that read message is proper and parmptr is properly loaded with the value. But in the function Where i am trying to call pipe_input I am getting a sigsegv. This happens with GCC-4.7.0 but the same code compiled with GCC-4.2.4 executes fine. I verified the warnings, but there are no warning for the above. Any pointers would be highly helpful.
Below code snippet for calling pipe_input :
int Calling_func(void)
{
char alpha[100] ;
pipe_input(alpha,100);
printf("alpha value is %s \r\n",alpha);
}
getting sigsegv at the print statement.
You have off-by-one errors in your code. Your array has 100 elements, but you're not taking NULL-termination into account:
strncpy(parmPtr, readMsg, ((size < 100)?size:100));
and:
buffer[nread]='\0';
The last element is buffer[99] (since array indices start from 0, not 1,) but you can write to buffer[100]. This can result in a segfault.
You should probably declare all arrays with a size of 101 instead and see if it helps. If you're on Linux, you should also run your program in Valgrind; it can tell you exactly how the segfault occurred.
I'm Trying to read from a socket and print to stdout using printf (a must);
However I get a Segmentation Fault every time I read a specific file (an HTML) from the sane web site.
Please, take a look at this code and tell me what wrong.
int total_read = 0;
char* read_buff = malloc(BUF_SIZE);
char* response_data = NULL;
if (read_buff == NULL){
perror("malloc");
exit(1);
}
while((nbytes = read(fd, read_buff, BUF_SIZE)) > 0){
int former_total = total_read;
total_read += nbytes;
response_data = realloc(response_data, total_read);
memmove(response_data + former_total, read_buff, nbytes); //start writing at the end of spot before the increase.
}
if (nbytes < 0){
perror("read");
exit(1);
}
printf(response_data);
Thank You.
response_data is probably not NUL ('\0') terminated, so printf continues past the end of the string. Or possibly it contains a % directive but printf can't find further arguments.
Instead, tell printf how far to read, and not to interpret any % directives in the string.
printf("%.*s", total_read, response_data);
Note that if response_data contains an embedded NUL, printf will stop there even if total_read is longer.
What's likely to be in response_data? If it contains printf-formatting characters (i.e. % followed by one of the usual options), printf will try to access some parameters you've not passed, and a segmentation fault is quite likely. Try puts instead?
If you must use printf, do printf("%s", response_data) (and NUL-terminate it first)
My understanding from your post is that the response is the HTML data.
And since it is text you attempt to print it. Do not use printf the way you do.
Instead do the following:
for(int i = 0; i < total_read; i++)
putc(response_data[i],stdout);
I've recently installed "klocwork" and am trying to get rid of bugs on an existing code.
The error shown seems to be simple. No null at the termination of the char * _p_.
I have manually added a null termination (even though there is no need), but it doesn't please the Klocwork. Any ideas?
The exact message is:-
Incorrectly terminated string 'p' causes a buffer overflow in p.
char *ptr;
int writtenchars = 0 ;
va_list args;
char* destStr;
if (argc != 2) {
printf(" wrong parameters number - %d instead of %d\n", argc, 2);
char str[25]="wrong parameters number ";
char *_p_; /********************************************************/
va_start(args, str);
destStr = (char*) malloc(SNMP_BUF_LEN);
_p_= destStr;
if (destStr == NULL) {
printf("WARNING: Failed to alloc memory in in function \"snmp_rebuildstringinbuf!!!\" \n");
destStr="kukuRiko";
}
else {
writtenchars = (int) vsnprintf(destStr, 4095, str, args);
if (writtenchars>SNMP_BUF_LEN) {
printf("WARNING: Too long string rebuilded in function \"snmp_rebuildstringinbuf!!!\" %d chars\n",writtenchars);
}
destStr[writtenchars] = '\0' ; //Moshe - making sure the last value of the string is null terminated in order to prevent future buffer overflows.
}
va_end(args);
/******************************************************************************/
//The KlocWork error relates to this line //
logCWriteLog_msg(moduleId, level, __FILE__, __LINE__, _p_, ltrue);
free (_p_);
===========================================================
Hi Guys,
Thanks for your answers, but it seems a bit more obscure than that. I have refined the code to this simple case:-
When the code is written all in one function there is no error, whereas, when the allocation section is wrapped in a function (and a text passed as parameter) the Klocwork error returns.
See this code:- version without an error:-
char *_p_; /*+++++++++++++++++++*/
int writtenchars = 0 ;
va_list args;
char* destStr;
char* str = "hello World";
va_start(args, str);
destStr = (char*)malloc(SNMP_BUF_LEN);
if (destStr == NULL) {
printf("WARNING: Failed to alloc memory in function \n");
}
else {
writtenchars = (int) vsnprintf(destStr, (SNMP_BUF_LEN) - 1, str, args);
}
/*+++++++++++++++++++*/
_p_ = destStr ;
if (_p_ != NULL) {
logCWriteLog_msg(moduleId, level, __FILE__, __LINE__, _p_, ltrue);
}
free (_p_);
/***********************************************************/
whereas when taking the code between /*++++ */ and wrapping it in a function returns the above KlocWork error.
Hence,
char *writingToSomeBuffer (char * str) {
int writtenchars = 0 ;
va_list args;
char* destStr;
va_start(args, str);
destStr = (char*)malloc(SNMP_BUF_LEN);
if (destStr == NULL) {
printf("WARNING: Failed to alloc memory in function \n");
}
else {
writtenchars = (int) vsnprintf(destStr, (SNMP_BUF_LEN) - 1, str, args);
}
return destStr;
}
int main () {
char *_p_;
_p_ = writingToSomeBuffer("hello world");
if (_p_ != NULL) {
logCWriteLog_msg(moduleId, level, __FILE__, __LINE__, _p_, ltrue);
}
free (_p_);
return 0 ;
}
any ideas?
KlocWork is correctly diagnosing the problem that you can be writing with a null pointer if memory allocation fails:
_p_= destStr;
if (destStr == NULL)
{
printf("WARNING: Failed to alloc memory in in function ...\n");
destStr = "kukuRiko";
At this point, the (horribly named) '_p_' variable is still null, but you go ahead and use it in the printing operation below.
Also note that the 'trivial' fix of adding '_p_' after this breaks your memory management; you later do 'free(_p_);' which will lead to horrible problems if '_p_' points to the constant string.
You also have 'memory in in function' in the message. And 'wrong parameters number' does mean roughly the same as 'wrong number of parameters' but the latter is more idiomatic English. I'm not convinced any of the exclamation marks are helpful in the error message; there is a strong argument that they should go outside the double quotes surrounding the function name even if one of them is deemed desirable.
With the revised version of the problem, I wonder if Klocwork is diagnosing what Microsoft says of its vsnprintf(), that it does not guarantee null termination (which is different from what C99 and POSIX says).
Jonathan has it right. We've recently broken up this checker into two families that might explain it better:
http://www.klocwork.com/products/documentation/Insight-9.1/Checkers:NNTS.MIGHT
http://www.klocwork.com/products/documentation/Insight-9.1/Checkers:NNTS.MUST
We are currently under development to clean this up and make it easier to understand. Not only the problem but the solution as well.
Klocwork's error aside, I think this code is wrong. Why are you limiting the vsnprintf to 4096, while the buffer size is SNMP_BUF_LEN? How do those two related to each other? If SNMP_BUF_LEN < 4096, then you may have just overflowed your buffer. Why wouldn't you pass SNMP_BUF_LEN as the limiting argument in vsnprintf?
Also, the write to destStr[writtenchars] is suspect. Depending on the variant of vsnprintf (they do vary), writtenchars might be the number of characters it wanted to write, which would again cause you to write past the end of your buffer.
That all said, Klocwork isn't perfect. We had macros that were very explicitly trying to be safe, and Klocwork mis-detected them as potentially overrunning the string. I think that was a snprintf case as well.
Overall a good product, but it does have a few holes and you can't fix all it's complaints.