Fix potential memory leak in cpu enumeration on Linux (#2008)
authorMartin Kroeker <martin@ruby.chemie.uni-freiburg.de>
Sun, 10 Feb 2019 22:24:45 +0000 (23:24 +0100)
committerGitHub <noreply@github.com>
Sun, 10 Feb 2019 22:24:45 +0000 (23:24 +0100)
* 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

driver/others/memory.c

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