wmtop: Use proper int types.
Based partially on a patch by wbk to fix Gentoo bug #410093 [1]. From the bug report: After fixing the /proc/meminfo issue, another bug will emerge on systems where total system RAM in bytes exceeds INT_MAX. The correct top three processes will be identified, but their load bars will have the wrong value. This is caused by a value overflow due to storing total system memory in an "int" type variable. We will end up thinking ((Total RAM) modulo (INT_MAX)) is our total system RAM, so our percentages will be inflated when drawing the load bar. This fix will require a bit more care to follow the flow of data and ensure this value isn't being cast to "int" along the way. Function return types will need to be changed. [1] https://bugs.gentoo.org/show_bug.cgi?id=410093
This commit is contained in:
		
							parent
							
								
									9450f4cfd2
								
							
						
					
					
						commit
						5fd5619cc4
					
				
					 1 changed files with 37 additions and 27 deletions
				
			
		| 
						 | 
					@ -185,12 +185,12 @@ struct process {
 | 
				
			||||||
    pid_t pid;
 | 
					    pid_t pid;
 | 
				
			||||||
    char *name;
 | 
					    char *name;
 | 
				
			||||||
    float amount;
 | 
					    float amount;
 | 
				
			||||||
    int user_time;
 | 
					    unsigned long user_time;
 | 
				
			||||||
    int kernel_time;
 | 
					    unsigned long kernel_time;
 | 
				
			||||||
    int previous_user_time;
 | 
					    unsigned long previous_user_time;
 | 
				
			||||||
    int previous_kernel_time;
 | 
					    unsigned long previous_kernel_time;
 | 
				
			||||||
    int vsize;
 | 
					    unsigned long vsize;
 | 
				
			||||||
    int rss;
 | 
					    long rss;
 | 
				
			||||||
    int time_stamp;
 | 
					    int time_stamp;
 | 
				
			||||||
    int counted;
 | 
					    int counted;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					@ -239,8 +239,8 @@ struct process *new_process(int p) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    process->pid = p;
 | 
					    process->pid = p;
 | 
				
			||||||
    process->time_stamp = 0;
 | 
					    process->time_stamp = 0;
 | 
				
			||||||
    process->previous_user_time = INT_MAX;
 | 
					    process->previous_user_time = ULONG_MAX;
 | 
				
			||||||
    process->previous_kernel_time = INT_MAX;
 | 
					    process->previous_kernel_time = ULONG_MAX;
 | 
				
			||||||
    process->counted = 1;
 | 
					    process->counted = 1;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*    process_find_name(process);*/
 | 
					/*    process_find_name(process);*/
 | 
				
			||||||
| 
						 | 
					@ -259,11 +259,11 @@ int calculate_cpu(struct process *);
 | 
				
			||||||
void process_cleanup(void);
 | 
					void process_cleanup(void);
 | 
				
			||||||
void delete_process(struct process *);
 | 
					void delete_process(struct process *);
 | 
				
			||||||
void draw_processes(void);
 | 
					void draw_processes(void);
 | 
				
			||||||
int calc_cpu_total(void);
 | 
					unsigned long calc_cpu_total(void);
 | 
				
			||||||
void calc_cpu_each(int);
 | 
					void calc_cpu_each(unsigned long total);
 | 
				
			||||||
#if defined(LINUX)
 | 
					#if defined(LINUX)
 | 
				
			||||||
int calc_mem_total(void);
 | 
					unsigned long calc_mem_total(void);
 | 
				
			||||||
void calc_mem_each(int);
 | 
					void calc_mem_each(unsigned long total);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
int process_find_top_three(struct process **);
 | 
					int process_find_top_three(struct process **);
 | 
				
			||||||
void draw_bar(int, int, int, int, float, int, int);
 | 
					void draw_bar(int, int, int, int, float, int, int);
 | 
				
			||||||
| 
						 | 
					@ -460,7 +460,7 @@ int process_parse_procfs(struct process *process) {
 | 
				
			||||||
    char line[WMTOP_BUFLENGTH],filename[WMTOP_BUFLENGTH],procname[WMTOP_BUFLENGTH];
 | 
					    char line[WMTOP_BUFLENGTH],filename[WMTOP_BUFLENGTH],procname[WMTOP_BUFLENGTH];
 | 
				
			||||||
    int ps;
 | 
					    int ps;
 | 
				
			||||||
    struct stat sbuf;
 | 
					    struct stat sbuf;
 | 
				
			||||||
    int user_time,kernel_time;
 | 
					    unsigned long user_time,kernel_time;
 | 
				
			||||||
    int rc;
 | 
					    int rc;
 | 
				
			||||||
#if defined(LINUX)
 | 
					#if defined(LINUX)
 | 
				
			||||||
    char *r,*q;
 | 
					    char *r,*q;
 | 
				
			||||||
| 
						 | 
					@ -468,6 +468,8 @@ int process_parse_procfs(struct process *process) {
 | 
				
			||||||
		int endl;
 | 
							int endl;
 | 
				
			||||||
#endif /* defined(LINUX) */
 | 
					#endif /* defined(LINUX) */
 | 
				
			||||||
#if defined(FREEBSD)
 | 
					#if defined(FREEBSD)
 | 
				
			||||||
 | 
					    /* TODO: needs analysis. Probably needs same data type fix as LINUX (use
 | 
				
			||||||
 | 
					     * long types). Need to check FreeBSD docs and test.  -wbk		     */
 | 
				
			||||||
    int us,um,ks,km;
 | 
					    int us,um,ks,km;
 | 
				
			||||||
#endif /* defined(FREEBSD) */
 | 
					#endif /* defined(FREEBSD) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -505,9 +507,10 @@ int process_parse_procfs(struct process *process) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(LINUX)
 | 
					#if defined(LINUX)
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * Extract cpu times from data in /proc filesystem
 | 
					     * Extract cpu times from data in /proc filesystem.
 | 
				
			||||||
 | 
					     * For conversion types see man proc(5).
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    rc = sscanf(line,"%*s %s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %d %d %*s %*s %*s %*s %*s %*s %*s %d %d",
 | 
					    rc = sscanf(line,"%*s %s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %*s %lu %lu %*s %*s %*s %*s %*s %*s %*s %lu %ld",
 | 
				
			||||||
	    procname,
 | 
						    procname,
 | 
				
			||||||
	    &process->user_time,&process->kernel_time,
 | 
						    &process->user_time,&process->kernel_time,
 | 
				
			||||||
	    &process->vsize,&process->rss);
 | 
						    &process->vsize,&process->rss);
 | 
				
			||||||
| 
						 | 
					@ -572,6 +575,9 @@ int process_parse_procfs(struct process *process) {
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * Extract cpu times from data in /proc/<pid>/stat
 | 
					     * Extract cpu times from data in /proc/<pid>/stat
 | 
				
			||||||
     * XXX: Process name extractor for FreeBSD is untested right now.
 | 
					     * XXX: Process name extractor for FreeBSD is untested right now.
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * [TODO: FREEBSD code probably needs similar data type changes to 
 | 
				
			||||||
 | 
					     * those made for LINUX above. Need to check docs.			-wbk]
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    rc = sscanf(line,"%s %*s %*s %*s %*s %*s %*s %*s %d,%d %d,%d",
 | 
					    rc = sscanf(line,"%s %*s %*s %*s %*s %*s %*s %*s %d,%d %d,%d",
 | 
				
			||||||
	    procname,
 | 
						    procname,
 | 
				
			||||||
| 
						 | 
					@ -585,11 +591,14 @@ int process_parse_procfs(struct process *process) {
 | 
				
			||||||
    process->kernel_time = ks*1000+km/1000;
 | 
					    process->kernel_time = ks*1000+km/1000;
 | 
				
			||||||
#endif /* defined(FREEBSD) */
 | 
					#endif /* defined(FREEBSD) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /* not portable (especially unsuitable for redistributable executables.
 | 
				
			||||||
 | 
					     * On some systems, getpagesize() is a preprocessor macro).
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
    process->rss *= getpagesize();
 | 
					    process->rss *= getpagesize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (process->previous_user_time==INT_MAX)
 | 
					    if (process->previous_user_time==ULONG_MAX)
 | 
				
			||||||
	process->previous_user_time = process->user_time;
 | 
						process->previous_user_time = process->user_time;
 | 
				
			||||||
    if (process->previous_kernel_time==INT_MAX)
 | 
					    if (process->previous_kernel_time==ULONG_MAX)
 | 
				
			||||||
	process->previous_kernel_time = process->kernel_time;
 | 
						process->previous_kernel_time = process->kernel_time;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    user_time = process->user_time-process->previous_user_time;
 | 
					    user_time = process->user_time-process->previous_user_time;
 | 
				
			||||||
| 
						 | 
					@ -731,7 +740,7 @@ void delete_process(struct process *p) {
 | 
				
			||||||
void draw_processes() {
 | 
					void draw_processes() {
 | 
				
			||||||
    int i,n;
 | 
					    int i,n;
 | 
				
			||||||
    struct process *best[3] = { 0, 0, 0 };
 | 
					    struct process *best[3] = { 0, 0, 0 };
 | 
				
			||||||
    int total;
 | 
					    unsigned long total;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * Invalidate time stamps
 | 
					     * Invalidate time stamps
 | 
				
			||||||
| 
						 | 
					@ -788,21 +797,21 @@ void draw_processes() {
 | 
				
			||||||
/* Calculate cpu total                    */
 | 
					/* Calculate cpu total                    */
 | 
				
			||||||
/******************************************/
 | 
					/******************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
int calc_cpu_total() {
 | 
					unsigned long calc_cpu_total() {
 | 
				
			||||||
    int total,t;
 | 
					    unsigned long total,t;
 | 
				
			||||||
    static int previous_total = INT_MAX;
 | 
					    static unsigned long previous_total = ULONG_MAX;
 | 
				
			||||||
#if defined(LINUX)
 | 
					#if defined(LINUX)
 | 
				
			||||||
    int rc;
 | 
					    int rc;
 | 
				
			||||||
    int ps;
 | 
					    int ps;
 | 
				
			||||||
    char line[WMTOP_BUFLENGTH];
 | 
					    char line[WMTOP_BUFLENGTH];
 | 
				
			||||||
    int cpu,nice,system,idle;
 | 
					    unsigned long cpu,nice,system,idle;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ps = open("/proc/stat",O_RDONLY);
 | 
					    ps = open("/proc/stat",O_RDONLY);
 | 
				
			||||||
    rc = read(ps,line,sizeof(line));
 | 
					    rc = read(ps,line,sizeof(line));
 | 
				
			||||||
    close(ps);
 | 
					    close(ps);
 | 
				
			||||||
    if (rc<0)
 | 
					    if (rc<0)
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
    sscanf(line,"%*s %d %d %d %d",&cpu,&nice,&system,&idle);
 | 
					    sscanf(line,"%*s %lu %lu %lu %lu",&cpu,&nice,&system,&idle);
 | 
				
			||||||
    total = cpu+nice+system+idle;
 | 
					    total = cpu+nice+system+idle;
 | 
				
			||||||
#endif /* defined(LINUX) */
 | 
					#endif /* defined(LINUX) */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -825,7 +834,7 @@ int calc_cpu_total() {
 | 
				
			||||||
/* Calculate each processes cpu           */
 | 
					/* Calculate each processes cpu           */
 | 
				
			||||||
/******************************************/
 | 
					/******************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void calc_cpu_each(int total) {
 | 
					void calc_cpu_each(unsigned long total) {
 | 
				
			||||||
    struct process *p = first_process;
 | 
					    struct process *p = first_process;
 | 
				
			||||||
    while (p) {
 | 
					    while (p) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -843,7 +852,8 @@ void calc_cpu_each(int total) {
 | 
				
			||||||
/******************************************/
 | 
					/******************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(LINUX)
 | 
					#if defined(LINUX)
 | 
				
			||||||
int calc_mem_total() {
 | 
					/* INT_MAX won't always hold total system RAM, especially on a 64 bit system. */
 | 
				
			||||||
 | 
					unsigned long calc_mem_total() {
 | 
				
			||||||
    int ps;
 | 
					    int ps;
 | 
				
			||||||
    char line[1024];
 | 
					    char line[1024];
 | 
				
			||||||
    char *ptr;
 | 
					    char *ptr;
 | 
				
			||||||
| 
						 | 
					@ -873,10 +883,10 @@ int calc_mem_total() {
 | 
				
			||||||
/******************************************/
 | 
					/******************************************/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#if defined(LINUX)
 | 
					#if defined(LINUX)
 | 
				
			||||||
void calc_mem_each(int total) {
 | 
					void calc_mem_each(unsigned long total) {
 | 
				
			||||||
    struct process *p = first_process;
 | 
					    struct process *p = first_process;
 | 
				
			||||||
    while (p) {
 | 
					    while (p) {
 | 
				
			||||||
	p->amount = 100*(float)p->rss/total;
 | 
						p->amount = 100*(double)p->rss/total;
 | 
				
			||||||
	p = p->next;
 | 
						p = p->next;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue