20861, "twesterhout", "Global variables are not always initialized", "2022-10-14T16:02:53Z"
Summary of Problem
This issue has been briefly discussed with @bradcray on Gitter, and I promised to create a reproducer. Also pinging @vasslitvinov because he's attempted to reproduce the issue at some point.
The problem is that sometimes, in multi-locale builds, global variables are not initialized which results in segfaults or "attempt to dereference null" errors.
Example output of the program:
1
1
src/error.chpl:40: error: attempt to dereference nil
Stacktrace
sizeAs() at $CHPL_HOME/modules/internal/ChapelDomain.chpl:1952
size() at $CHPL_HOME/modules/internal/ChapelDomain.chpl:1947
size() at $CHPL_HOME/modules/internal/ChapelArray.chpl:1397
foo() at src/error.chpl:20
bar() at src/error.chpl:18
on_fn() at src/error.chpl:55
wrapon_fn() at src/error.chpl:55
Steps to Reproduce
src/error.chpl:
use CTypes;
use AllLocalesBarriers;
config param shouldCrash : bool = true;
var globalDom : domain(1, int);
var globalArr : [globalDom] atomic real;
class GlobalBuffer {
var dom : domain(1, int);
var arr : [dom] atomic real;
}
var alternative = new GlobalBuffer();
require "error_header.h";
extern proc bar(procID : c_int, size : c_int);
export proc foo(sendBuf : c_ptr(real), recvBuf : c_ptr(real), count : c_ptr(c_int)) {
allLocalesBarrier.barrier();
const n = count.deref():int;
const indices = 0 ..# n;
ref dom = if shouldCrash then globalDom else alternative.dom;
ref arr = if shouldCrash then globalArr else alternative.arr;
// Grow the buffer if it's not big enough
if here.id == 0 {
if n > dom.size then
dom = {indices};
// IMPORTANT!
arr.write(0, memoryOrder.relaxed);
}
// Make sure locale 0 has had the chance to resize before proceeding
allLocalesBarrier.barrier();
assert(arr.size >= n);
// Have all locales atomically add their results to the atomicBuff
forall i in indices do
arr[i].add(sendBuf[i], memoryOrder.relaxed);
// Make sure all locales have accumulated their contributions
allLocalesBarrier.barrier();
// Have each locale copy the results out into its buffer
forall i in indices do
recvBuf[i] = arr[i].read();
}
proc main() {
coforall loc in Locales do on loc {
for i in 1 .. 5 {
writeln(i);
bar(loc.id:c_int, i:c_int);
}
}
}
src/error.c:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
extern void foo(double const *sendBuf, double *recvBuf, int const *count);
void bar(int procID, int size) {
double *send = malloc(size * sizeof(double));
double *recv = malloc(size * sizeof(double));
assert(send != NULL);
assert(recv != NULL);
for (int i = 0; i < size; ++i) {
send[i] = (double)procID;
}
foo(send, recv, &size);
for (int i = 0; i < size; ++i) {
fprintf(stderr, "%f, ", recv[i]);
}
fprintf(stderr, "\n");
free(send);
free(recv);
}
src/error_header.h:
#pragma once
void bar(int procID, int size);
Compile command:
chpl -o error -sshouldCrash=true -I src/ src/error.chpl src/error.c
(NOTE: compiling with shouldCrash=false fixes the issue)
Execution command:
./error -nl2
Configuration Information
- Output of
chpl --version: chpl version 1.28.0 pre-release (3d54c9f456) - Output of
$CHPL_HOME/util/printchplenv --anonymize:
CHPL_TARGET_PLATFORM: linux64
CHPL_TARGET_COMPILER: llvm
CHPL_TARGET_ARCH: x86_64
CHPL_TARGET_CPU: native *
CHPL_LOCALE_MODEL: flat
CHPL_COMM: gasnet *
CHPL_COMM_SUBSTRATE: smp *
CHPL_GASNET_SEGMENT: fast
CHPL_TASKS: qthreads
CHPL_LAUNCHER: smp
CHPL_TIMERS: generic
CHPL_UNWIND: bundled *
CHPL_MEM: jemalloc
CHPL_ATOMICS: cstdlib
CHPL_NETWORK_ATOMICS: none
CHPL_GMP: none *
CHPL_HWLOC: bundled *
CHPL_RE2: none *
CHPL_LLVM: system *
CHPL_AUX_FILESYS: none