Skip to content

Commit 613e3b2

Browse files
authored
Merge pull request #2997 from Flamefire/reproduce_crash
Add reproducer test for crash after fork
2 parents 05a0ea2 + a05dc6e commit 613e3b2

File tree

4 files changed

+140
-4
lines changed

4 files changed

+140
-4
lines changed

utest/CMakeLists.txt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,17 @@ endif ()
2727

2828
# known to hang with the native Windows and Android threads
2929
# FIXME needs checking if this works on any of the other platforms
30-
if (NOT USE_OPENMP)
3130
if (OS_CYGWIN_NT OR OS_LINUX)
31+
if (NOT USE_OPENMP)
3232
set(OpenBLAS_utest_src
3333
${OpenBLAS_utest_src}
3434
test_fork.c
3535
)
3636
endif()
37+
set(OpenBLAS_utest_src
38+
${OpenBLAS_utest_src}
39+
test_post_fork.c
40+
)
3741
endif()
3842

3943
if (NOT NO_LAPACK)

utest/Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@ endif
2525

2626
#this does not work with OpenMP nor with native Windows or Android threads
2727
# FIXME TBD if this works on OSX, SunOS, POWER and zarch
28-
ifndef USE_OPENMP
2928
ifeq ($(OSNAME), $(filter $(OSNAME),Linux CYGWIN_NT))
29+
ifneq ($(USE_OPENMP), 1)
3030
OBJS += test_fork.o
3131
endif
32+
OBJS += test_post_fork.o
3233
endif
3334

3435
ifeq ($(C_COMPILER), PGI)

utest/test_fork.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3636
#include <cblas.h>
3737
#include "openblas_utest.h"
3838

39-
void* xmalloc(size_t n)
39+
static void* xmalloc(size_t n)
4040
{
4141
void* tmp;
4242
tmp = malloc(n);
@@ -49,7 +49,7 @@ void* xmalloc(size_t n)
4949
}
5050

5151
#ifdef BUILD_DOUBLE
52-
void check_dgemm(double *a, double *b, double *result, double *expected, blasint n)
52+
static void check_dgemm(double *a, double *b, double *result, double *expected, blasint n)
5353
{
5454
char trans1 = 'T';
5555
char trans2 = 'N';

utest/test_post_fork.c

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*****************************************************************************
2+
Copyright (c) 2011-2020, The OpenBLAS Project
3+
All rights reserved.
4+
5+
Redistribution and use in source and binary forms, with or without
6+
modification, are permitted provided that the following conditions are
7+
met:
8+
9+
1. Redistributions of source code must retain the above copyright
10+
notice, this list of conditions and the following disclaimer.
11+
12+
2. Redistributions in binary form must reproduce the above copyright
13+
notice, this list of conditions and the following disclaimer in
14+
the documentation and/or other materials provided with the
15+
distribution.
16+
3. Neither the name of the OpenBLAS project nor the names of
17+
its contributors may be used to endorse or promote products
18+
derived from this software without specific prior written
19+
permission.
20+
21+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24+
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
25+
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
30+
USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31+
32+
**********************************************************************************/
33+
34+
#include <sys/types.h>
35+
#include <sys/wait.h>
36+
#include <cblas.h>
37+
#ifdef USE_OPENMP
38+
#include <omp.h>
39+
#endif
40+
#include "openblas_utest.h"
41+
42+
static void* xmalloc(size_t n)
43+
{
44+
void* tmp;
45+
tmp = malloc(n);
46+
if (tmp == NULL) {
47+
fprintf(stderr, "You are about to die\n");
48+
exit(1);
49+
} else {
50+
return tmp;
51+
}
52+
}
53+
54+
#ifdef BUILD_DOUBLE
55+
static void check_dgemm(double *a, double *b, double *result, double *expected, blasint n)
56+
{
57+
char trans1 = 'T';
58+
char trans2 = 'N';
59+
double zerod = 0, oned = 1;
60+
int i;
61+
BLASFUNC(dgemm)(&trans1, &trans2, &n, &n, &n, &oned, a, &n, b, &n, &zerod, result, &n);
62+
for(i = 0; i < n * n; ++i) {
63+
ASSERT_DBL_NEAR_TOL(expected[i], result[i], DOUBLE_EPS);
64+
}
65+
}
66+
#endif
67+
68+
CTEST(fork, safety_after_fork_in_parent)
69+
{
70+
#ifndef BUILD_DOUBLE
71+
exit(0);
72+
#else
73+
blasint n = 100;
74+
int i, nthreads_omp;
75+
76+
double *a, *b, *c, *d;
77+
size_t n_bytes;
78+
79+
pid_t fork_pid;
80+
81+
n_bytes = sizeof(*a) * n * n;
82+
83+
a = xmalloc(n_bytes);
84+
b = xmalloc(n_bytes);
85+
c = xmalloc(n_bytes);
86+
d = xmalloc(n_bytes);
87+
88+
// Put ones in a, b and n in c (result)
89+
for(i = 0; i < n * n; ++i) {
90+
a[i] = 1;
91+
b[i] = 1;
92+
c[i] = 1 * n;
93+
}
94+
95+
// Test that OpenBLAS works after a fork.
96+
// This situation routinely happens with Pythons numpy where a
97+
// `sys.platform` calls `uname` in a forked process.
98+
// So we simulate this situation here.
99+
100+
// There was an issue where a different number of OpenBLAS and OpenMP
101+
// threads triggered a memory leak. So run this multiple times
102+
// with different number of threads set.
103+
#ifdef USE_OPENMP
104+
nthreads_omp = omp_get_max_threads();
105+
// Run with half the max OMP threads, the max threads and twice that
106+
for(i = (nthreads_omp + 1) / 2; i <= nthreads_omp * 2; i *= 2) {
107+
omp_set_num_threads(i);
108+
#endif
109+
110+
fork_pid = fork();
111+
if (fork_pid == -1) {
112+
CTEST_ERR("Failed to fork process.");
113+
} else if (fork_pid == 0) {
114+
// Just pretend to do something, e.g. call `uname`, then exit
115+
exit(0);
116+
} else {
117+
// Wait for the child to finish and check the exit code.
118+
int child_status = 0;
119+
pid_t wait_pid = wait(&child_status);
120+
ASSERT_EQUAL(wait_pid, fork_pid);
121+
ASSERT_EQUAL(0, WEXITSTATUS (child_status));
122+
123+
// Now OpenBLAS has to work
124+
check_dgemm(a, b, d, c, n);
125+
}
126+
#ifdef USE_OPENMP
127+
}
128+
#endif
129+
130+
#endif
131+
}

0 commit comments

Comments
 (0)