SIGSEGV on strftime (libc.so.6) 使用 gcc (GCC) 5.3.0
SIGSEGV on strftime (libc.so.6) using gcc (GCC) 5.3.0
我有一个用 c 编写的 http 客户端,在某些部分我得到时间并填写缓冲区,我检查了所有输入值是否有效,但是当函数 运行s 它给出分段时故障,行号 77,行:
strftime(timebuf, sizeof(timebuf), RFC1123FMT, gmtime(&now));
我用调试器测试了输入,没有一个是有问题的
使用此命令编译 运行 后
./COMPILED_FILE_NAME https://whosebug.com/ -d 1:1:1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/types.h>
#define HEADER "-h"
#define TIME_STAMP "-d"
#define PROTOCOL "http://"
#define RFC1123FMT "%a, %d %b %Y %H:%M:%S GMT"
#define DEFAULT_PORT 80
#define BUFFER_SIZE 256
typedef struct sockaddr_in sockaddr_t;
void printError(int flag,char * name);
int parseUrl(char * url,char** host,int * portt ,char ** path);
int checkString(const char * date);
int parseDate(char* date,int * day,int * hour,int* minute);
void freeData();
int socketConnect(char * host,int port,char * page,char* requestType , char * dateRequest );
char * host; // the url with out any addititons
char * path; // the path after the url
int main(int argc,char * argv[])
{
time_t now;
now = time(NULL);
char timebuf[BUFFER_SIZE/2];
int headrFlag=0;
int timeFlag=0;
int day=0,hour=0,minute=0;
// char * host;//=(char*)malloc(sizeof(char)*128);
// char * path;//=(char*)malloc(sizeof(char)*128);
char requestType[BUFFER_SIZE];
char dateRequest[BUFFER_SIZE];
bzero(dateRequest,sizeof(dateRequest));
strcpy(requestType,"GET");
int port=DEFAULT_PORT;
if(argc >1 && argc <=5) // the host at least their
{
// checking the incoming args
int i = 1;
for(;i<argc;i++)
{
if(strcmp(argv[i],HEADER)==0)
{
if(headrFlag==0)
{
headrFlag=1;
strcpy(requestType,"HEAD");
}
else
{
printError(0,"");
break;
}
}
else if(strcmp(argv[i],TIME_STAMP)==0)
{
// take the date from the next i , if not there as error
if(timeFlag==0)
{
timeFlag=1;
if(i+1!=argc && parseDate(argv[i+1],&day,&hour,&minute)!=-1) // there is date "thing" after the flag
{
now=now-(day*24*3600+hour*3600+minute*60); //where day, hour and min are the values
//from the input
strftime(timebuf, sizeof(timebuf), RFC1123FMT, gmtime(&now));
//timebuf holds the correct format of the time
sprintf(dateRequest,"If-Modified-Since: %s\n",timebuf);
i++;
continue;
}
else
{
printError(1,"");
}
}
else
{
printError(0,"");
}
printError(0,"");
break;
}
else // the host
{
if(parseUrl(argv[i],&host,&port,&path)<0)
{
printError(1,"");
}
}
}
// connect after every thing is valid
if(host!=NULL){socketConnect(host,port,path,requestType,dateRequest);}else{printError(0,"");}
}
else
{
printError(1,"");
}
return 0;
}
void printError(int flag,char * name)
{
// 0 wrong command usage
//1 wrong input
//2 system call failure
if(flag==0)
{
printf("Usage: client [-h] [-d <time-interval>] <URL>\n");
}
else if(flag==1) // wrong input
{
printf("wring input\n");
}
else // flag ==2 , sys calls
{
perror(name);
}
freeData();
exit(-1);
}
// handles the validation of the url
int parseUrl(char * url,char** host,int * portt ,char ** path)
{
char * det=":";
char * det1="/";
char * port;
char * temp;
char * pathValue;
int pathSize=0,hostSize=0;
int addSize=0;
int portNumber=80;
char * urlToParse;
if((temp=strstr(url,PROTOCOL))!=NULL && temp==url) // checking http://
{
temp=&temp[strlen(PROTOCOL)];
urlToParse=temp;
if(strlen(urlToParse) <=1)
return -1;
}
else
{
return -1;
}
if((temp=strstr(temp,det))!=NULL) // checking port
{
int len1 = strlen(temp)-1; // length from the : to the end
addSize=len1;
char * temp1;
if((temp1=strstr(temp,det1))!=NULL)
{
pathSize= strlen(temp1);
pathValue=temp1;
int portLength= len1-pathSize;
port = (char*)malloc(sizeof(char)*portLength+1);
if(port==NULL)
{
printError(2,"malloc");
}
port[portLength]='[=11=]';
strncpy(port,++temp,portLength);
if(checkString(port)<0)
return -1;
portNumber=atoi(port);
free(port);
addSize=len1+1;
}
}
else // no port
{
temp=urlToParse;
if((temp=strstr(temp,det1))==NULL) // checking filepath
{
return -1;
}
else
{
pathValue=temp;
pathSize=strlen(temp);
addSize=pathSize;
}
}
hostSize=strlen(urlToParse)-addSize;
*host =(char*)malloc(sizeof(char)*(hostSize+1));
if(*host==NULL)
{
printError(2,"malloc");
}
**host=NULL;
* path =(char*)malloc(sizeof(char)*(pathSize+1));
if(*path==NULL)
{
printError(2,"malloc");
}
**path=NULL;
// *path=pathValue;
strcpy(*path,pathValue);
*portt=portNumber;
strncpy(*host,urlToParse,hostSize);
return 0;
}
// checks if the number is valid
int checkString(const char * date)
{
if(date==NULL || strcmp(date,"")==0)
{
return -1;
}
int len = strlen(date);
if(strlen(date)>1 && strncmp(&date[0],"-",1)==0 )
{
date++;
}
while(date && strcmp(date,"")!=0)
{
if(isdigit(*(date++))==0)
{
return -1;
}
}
return 1;
}
// converts from chars to int
int parseDate(char* date,int * day,int * hour,int* minute)
{
char * det=":";
// int days,hours,minutes;
char * dayss = strtok(date,det);
char * hourss = strtok(NULL,det);
char * moinutss = strtok(NULL,det);
if(dayss ==NULL || hourss==NULL||moinutss==NULL)
{
return -1;
}
if(checkString(dayss)<0 || checkString(hourss)<0 || checkString(moinutss)<0 )
return -1;
*day = atoi(dayss);
*hour= atoi(hourss);
*minute=atoi(moinutss);
return 1;
}
// free what ever memory we used
void freeData()
{
if(host !=NULL)
{
free(host);
}
if(path!=NULL)
{
free(path);
}
}
// handles the connection to the server
int socketConnect(char * host,int port,char * page,char* requestType , char * dateRequest )
{
struct in_addr serverIp;
struct hostent * hostt =NULL;
hostt= (struct hostent *)gethostbyname(host);
if(hostt==NULL)
{
freeData();
herror("");
printf("\n");
exit(0);
}
struct addr_in** addresses = (struct in_addr **)hostt->h_addr_list;
int i=0;
// char * ss= inet_ntoa(((struct in_addr*)hostt->h_addr)->s_addr);
// serverIp.s_addr=inet_addr(ss);
struct sockaddr_in packet;
packet.sin_family=AF_INET;
packet.sin_port=htons(port);
packet.sin_addr.s_addr=((struct in_addr*) hostt->h_addr)->s_addr;
int socketFd ;
if((socketFd=socket(PF_INET,SOCK_STREAM,0))<0)
{
printError(2,"socket");
}
if(connect(socketFd,(struct sockaddr*)&packet,sizeof(packet))<0)
{
printError(2,"connect");
}
char buffer[BUFFER_SIZE*4];
char * req = malloc(sizeof(requestType)+sizeof(page)+sizeof(dateRequest)+BUFFER_SIZE);
if(req==NULL)
{
freeData(2,"malloc");
}
sprintf(req,"%s http://%s%s HTTP/1.0\r\n%s\n",requestType,host,page,dateRequest);
printf("HTTP request =\n%s\nLEN = %d\n",req,strlen(req));
send(socketFd,req,strlen(req),0);
int sizeOfResponse=0;
int reading=0 ;
do
{
bzero(buffer,sizeof(buffer));
reading= read(socketFd,buffer,sizeof(buffer),0);
if(reading >0)
{
printf("%s",buffer);
sizeOfResponse=sizeOfResponse+strlen(buffer);
}
}
while(reading>0);
printf("\nTotal received response bytes: %d\n",sizeOfResponse);
close(socketFd);
free(req);
freeData();
}
根本原因:您必须 #include <time.h>
。
原因是如果没有范围内的声明,编译器会假定 gmtime()
returns int
。实际上它 returns struct tm *
,显然在您的平台上指针比整数宽。
您应该启用所有警告并注意它们。
我有一个用 c 编写的 http 客户端,在某些部分我得到时间并填写缓冲区,我检查了所有输入值是否有效,但是当函数 运行s 它给出分段时故障,行号 77,行:
strftime(timebuf, sizeof(timebuf), RFC1123FMT, gmtime(&now));
我用调试器测试了输入,没有一个是有问题的
使用此命令编译 运行 后
./COMPILED_FILE_NAME https://whosebug.com/ -d 1:1:1
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/types.h>
#define HEADER "-h"
#define TIME_STAMP "-d"
#define PROTOCOL "http://"
#define RFC1123FMT "%a, %d %b %Y %H:%M:%S GMT"
#define DEFAULT_PORT 80
#define BUFFER_SIZE 256
typedef struct sockaddr_in sockaddr_t;
void printError(int flag,char * name);
int parseUrl(char * url,char** host,int * portt ,char ** path);
int checkString(const char * date);
int parseDate(char* date,int * day,int * hour,int* minute);
void freeData();
int socketConnect(char * host,int port,char * page,char* requestType , char * dateRequest );
char * host; // the url with out any addititons
char * path; // the path after the url
int main(int argc,char * argv[])
{
time_t now;
now = time(NULL);
char timebuf[BUFFER_SIZE/2];
int headrFlag=0;
int timeFlag=0;
int day=0,hour=0,minute=0;
// char * host;//=(char*)malloc(sizeof(char)*128);
// char * path;//=(char*)malloc(sizeof(char)*128);
char requestType[BUFFER_SIZE];
char dateRequest[BUFFER_SIZE];
bzero(dateRequest,sizeof(dateRequest));
strcpy(requestType,"GET");
int port=DEFAULT_PORT;
if(argc >1 && argc <=5) // the host at least their
{
// checking the incoming args
int i = 1;
for(;i<argc;i++)
{
if(strcmp(argv[i],HEADER)==0)
{
if(headrFlag==0)
{
headrFlag=1;
strcpy(requestType,"HEAD");
}
else
{
printError(0,"");
break;
}
}
else if(strcmp(argv[i],TIME_STAMP)==0)
{
// take the date from the next i , if not there as error
if(timeFlag==0)
{
timeFlag=1;
if(i+1!=argc && parseDate(argv[i+1],&day,&hour,&minute)!=-1) // there is date "thing" after the flag
{
now=now-(day*24*3600+hour*3600+minute*60); //where day, hour and min are the values
//from the input
strftime(timebuf, sizeof(timebuf), RFC1123FMT, gmtime(&now));
//timebuf holds the correct format of the time
sprintf(dateRequest,"If-Modified-Since: %s\n",timebuf);
i++;
continue;
}
else
{
printError(1,"");
}
}
else
{
printError(0,"");
}
printError(0,"");
break;
}
else // the host
{
if(parseUrl(argv[i],&host,&port,&path)<0)
{
printError(1,"");
}
}
}
// connect after every thing is valid
if(host!=NULL){socketConnect(host,port,path,requestType,dateRequest);}else{printError(0,"");}
}
else
{
printError(1,"");
}
return 0;
}
void printError(int flag,char * name)
{
// 0 wrong command usage
//1 wrong input
//2 system call failure
if(flag==0)
{
printf("Usage: client [-h] [-d <time-interval>] <URL>\n");
}
else if(flag==1) // wrong input
{
printf("wring input\n");
}
else // flag ==2 , sys calls
{
perror(name);
}
freeData();
exit(-1);
}
// handles the validation of the url
int parseUrl(char * url,char** host,int * portt ,char ** path)
{
char * det=":";
char * det1="/";
char * port;
char * temp;
char * pathValue;
int pathSize=0,hostSize=0;
int addSize=0;
int portNumber=80;
char * urlToParse;
if((temp=strstr(url,PROTOCOL))!=NULL && temp==url) // checking http://
{
temp=&temp[strlen(PROTOCOL)];
urlToParse=temp;
if(strlen(urlToParse) <=1)
return -1;
}
else
{
return -1;
}
if((temp=strstr(temp,det))!=NULL) // checking port
{
int len1 = strlen(temp)-1; // length from the : to the end
addSize=len1;
char * temp1;
if((temp1=strstr(temp,det1))!=NULL)
{
pathSize= strlen(temp1);
pathValue=temp1;
int portLength= len1-pathSize;
port = (char*)malloc(sizeof(char)*portLength+1);
if(port==NULL)
{
printError(2,"malloc");
}
port[portLength]='[=11=]';
strncpy(port,++temp,portLength);
if(checkString(port)<0)
return -1;
portNumber=atoi(port);
free(port);
addSize=len1+1;
}
}
else // no port
{
temp=urlToParse;
if((temp=strstr(temp,det1))==NULL) // checking filepath
{
return -1;
}
else
{
pathValue=temp;
pathSize=strlen(temp);
addSize=pathSize;
}
}
hostSize=strlen(urlToParse)-addSize;
*host =(char*)malloc(sizeof(char)*(hostSize+1));
if(*host==NULL)
{
printError(2,"malloc");
}
**host=NULL;
* path =(char*)malloc(sizeof(char)*(pathSize+1));
if(*path==NULL)
{
printError(2,"malloc");
}
**path=NULL;
// *path=pathValue;
strcpy(*path,pathValue);
*portt=portNumber;
strncpy(*host,urlToParse,hostSize);
return 0;
}
// checks if the number is valid
int checkString(const char * date)
{
if(date==NULL || strcmp(date,"")==0)
{
return -1;
}
int len = strlen(date);
if(strlen(date)>1 && strncmp(&date[0],"-",1)==0 )
{
date++;
}
while(date && strcmp(date,"")!=0)
{
if(isdigit(*(date++))==0)
{
return -1;
}
}
return 1;
}
// converts from chars to int
int parseDate(char* date,int * day,int * hour,int* minute)
{
char * det=":";
// int days,hours,minutes;
char * dayss = strtok(date,det);
char * hourss = strtok(NULL,det);
char * moinutss = strtok(NULL,det);
if(dayss ==NULL || hourss==NULL||moinutss==NULL)
{
return -1;
}
if(checkString(dayss)<0 || checkString(hourss)<0 || checkString(moinutss)<0 )
return -1;
*day = atoi(dayss);
*hour= atoi(hourss);
*minute=atoi(moinutss);
return 1;
}
// free what ever memory we used
void freeData()
{
if(host !=NULL)
{
free(host);
}
if(path!=NULL)
{
free(path);
}
}
// handles the connection to the server
int socketConnect(char * host,int port,char * page,char* requestType , char * dateRequest )
{
struct in_addr serverIp;
struct hostent * hostt =NULL;
hostt= (struct hostent *)gethostbyname(host);
if(hostt==NULL)
{
freeData();
herror("");
printf("\n");
exit(0);
}
struct addr_in** addresses = (struct in_addr **)hostt->h_addr_list;
int i=0;
// char * ss= inet_ntoa(((struct in_addr*)hostt->h_addr)->s_addr);
// serverIp.s_addr=inet_addr(ss);
struct sockaddr_in packet;
packet.sin_family=AF_INET;
packet.sin_port=htons(port);
packet.sin_addr.s_addr=((struct in_addr*) hostt->h_addr)->s_addr;
int socketFd ;
if((socketFd=socket(PF_INET,SOCK_STREAM,0))<0)
{
printError(2,"socket");
}
if(connect(socketFd,(struct sockaddr*)&packet,sizeof(packet))<0)
{
printError(2,"connect");
}
char buffer[BUFFER_SIZE*4];
char * req = malloc(sizeof(requestType)+sizeof(page)+sizeof(dateRequest)+BUFFER_SIZE);
if(req==NULL)
{
freeData(2,"malloc");
}
sprintf(req,"%s http://%s%s HTTP/1.0\r\n%s\n",requestType,host,page,dateRequest);
printf("HTTP request =\n%s\nLEN = %d\n",req,strlen(req));
send(socketFd,req,strlen(req),0);
int sizeOfResponse=0;
int reading=0 ;
do
{
bzero(buffer,sizeof(buffer));
reading= read(socketFd,buffer,sizeof(buffer),0);
if(reading >0)
{
printf("%s",buffer);
sizeOfResponse=sizeOfResponse+strlen(buffer);
}
}
while(reading>0);
printf("\nTotal received response bytes: %d\n",sizeOfResponse);
close(socketFd);
free(req);
freeData();
}
根本原因:您必须 #include <time.h>
。
原因是如果没有范围内的声明,编译器会假定 gmtime()
returns int
。实际上它 returns struct tm *
,显然在您的平台上指针比整数宽。
您应该启用所有警告并注意它们。