Fix potential memory leak in cpu enumeration on Linux (#2008)

* Fix potential memory leak in cpu enumeration with glibc

An early return after a failed call to sched_getaffinity would leak the previously allocated cpu_set_t. Wrong calculation of the size argument in that call increased the likelyhood of that failure. Fixes #2003
This commit is contained in:
Martin Kroeker 2019-02-10 23:24:45 +01:00 committed by GitHub
parent 69edc5bbe7
commit 03a2bf2602
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 85 additions and 38 deletions

View File

@ -198,45 +198,68 @@ int get_num_procs(void);
#else #else
int get_num_procs(void) { int get_num_procs(void) {
static int nums = 0; static int nums = 0;
cpu_set_t *cpusetp; cpu_set_t cpuset,*cpusetp;
size_t size; size_t size;
int ret; int ret;
int i,n;
#if defined(__GLIBC_PREREQ)
#if !__GLIBC_PREREQ(2, 7)
int i;
#if !__GLIBC_PREREQ(2, 6)
int n;
#endif
#endif
#endif
if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF); if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF);
#if !defined(OS_LINUX) #if !defined(OS_LINUX)
return nums; return nums;
#endif #endif
#if !defined(__GLIBC_PREREQ) #if !defined(__GLIBC_PREREQ)
return nums; return nums;
#else #else
#if !__GLIBC_PREREQ(2, 3) #if !__GLIBC_PREREQ(2, 3)
return nums; return nums;
#endif #endif
#if !__GLIBC_PREREQ(2, 7) #if !__GLIBC_PREREQ(2, 7)
ret = sched_getaffinity(0,sizeof(cpu_set_t), cpusetp); ret = sched_getaffinity(0,sizeof(cpuset), &cpuset);
if (ret!=0) return nums; if (ret!=0) return nums;
n=0; n=0;
#if !__GLIBC_PREREQ(2, 6) #if !__GLIBC_PREREQ(2, 6)
for (i=0;i<nums;i++) for (i=0;i<nums;i++)
if (CPU_ISSET(i,cpusetp)) n++; if (CPU_ISSET(i,cpuset)) n++;
nums=n; nums=n;
#else #else
nums = CPU_COUNT(sizeof(cpu_set_t),cpusetp); nums = CPU_COUNT(sizeof(cpuset),&cpuset);
#endif #endif
return nums; return nums;
#else #else
cpusetp = CPU_ALLOC(nums); if (nums >= CPU_SETSIZE) {
if (cpusetp == NULL) return nums; cpusetp = CPU_ALLOC(nums);
size = CPU_ALLOC_SIZE(nums); if (cpusetp == NULL) {
ret = sched_getaffinity(0,size,cpusetp); return nums;
if (ret!=0) return nums; }
ret = CPU_COUNT_S(size,cpusetp); size = CPU_ALLOC_SIZE(nums);
if (ret > 0 && ret < nums) nums = ret; ret = sched_getaffinity(0,size,cpusetp);
CPU_FREE(cpusetp); if (ret!=0) {
return nums; CPU_FREE(cpusetp);
return nums;
}
ret = CPU_COUNT_S(size,cpusetp);
if (ret > 0 && ret < nums) nums = ret;
CPU_FREE(cpusetp);
return nums;
} else {
ret = sched_getaffinity(0,sizeof(cpuset),&cpuset);
if (ret!=0) {
return nums;
}
ret = CPU_COUNT(&cpuset);
if (ret > 0 && ret < nums) nums = ret;
return nums;
}
#endif #endif
#endif #endif
} }
@ -1709,46 +1732,70 @@ void goto_set_num_threads(int num_threads) {};
int get_num_procs(void); int get_num_procs(void);
#else #else
int get_num_procs(void) { int get_num_procs(void) {
static int nums = 0; static int nums = 0;
cpu_set_t *cpusetp; cpu_set_t cpuset,*cpusetp;
size_t size; size_t size;
int ret; int ret;
int i,n;
#if defined(__GLIBC_PREREQ)
#if !__GLIBC_PREREQ(2, 7)
int i;
#if !__GLIBC_PREREQ(2, 6)
int n;
#endif
#endif
#endif
if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF); if (!nums) nums = sysconf(_SC_NPROCESSORS_CONF);
#if !defined(OS_LINUX) #if !defined(OS_LINUX)
return nums; return nums;
#endif #endif
#if !defined(__GLIBC_PREREQ) #if !defined(__GLIBC_PREREQ)
return nums; return nums;
#else #else
#if !__GLIBC_PREREQ(2, 3) #if !__GLIBC_PREREQ(2, 3)
return nums; return nums;
#endif #endif
#if !__GLIBC_PREREQ(2, 7) #if !__GLIBC_PREREQ(2, 7)
ret = sched_getaffinity(0,sizeof(cpu_set_t), cpusetp); ret = sched_getaffinity(0,sizeof(cpuset), &cpuset);
if (ret!=0) return nums; if (ret!=0) return nums;
n=0; n=0;
#if !__GLIBC_PREREQ(2, 6) #if !__GLIBC_PREREQ(2, 6)
for (i=0;i<nums;i++) for (i=0;i<nums;i++)
if (CPU_ISSET(i,cpusetp)) n++; if (CPU_ISSET(i,cpuset)) n++;
nums=n; nums=n;
#else #else
nums = CPU_COUNT(sizeof(cpu_set_t),cpusetp); nums = CPU_COUNT(sizeof(cpuset),&cpuset);
#endif #endif
return nums; return nums;
#else #else
cpusetp = CPU_ALLOC(nums); if (nums >= CPU_SETSIZE) {
if (cpusetp == NULL) return nums; cpusetp = CPU_ALLOC(nums);
size = CPU_ALLOC_SIZE(nums); if (cpusetp == NULL) {
ret = sched_getaffinity(0,size,cpusetp); return nums;
if (ret!=0) return nums; }
ret = CPU_COUNT_S(size,cpusetp); size = CPU_ALLOC_SIZE(nums);
if (ret > 0 && ret < nums) nums = ret; ret = sched_getaffinity(0,size,cpusetp);
CPU_FREE(cpusetp); if (ret!=0) {
return nums; CPU_FREE(cpusetp);
return nums;
}
ret = CPU_COUNT_S(size,cpusetp);
if (ret > 0 && ret < nums) nums = ret;
CPU_FREE(cpusetp);
return nums;
} else {
ret = sched_getaffinity(0,sizeof(cpuset),&cpuset);
if (ret!=0) {
return nums;
}
ret = CPU_COUNT(&cpuset);
if (ret > 0 && ret < nums) nums = ret;
return nums;
}
#endif #endif
#endif #endif
} }