#!/usr/bin/env dub
/+ dub.sdl:
name "sanitizers_lsan_gc_interplay"
platforms "linux"
targetPath "build"
dflags "-g"
dflags "-fsanitize=leak" platform="ldc"
+/
/**
* Standalone LeakSanitizer vs the D garbage collector, four quadrants — the
* blind spots a `--sanitize=leak` runner mode must document:
*
* 1. Q1 `malloc(1001)`, unreachable -> reported (true leak).
* 2. Q2 `malloc(2002)` referenced ONLY from a GC array -> reported anyway:
* a FALSE POSITIVE. LSan's flood fill follows pointers only through its
* own allocator's chunks (compiler-rt `lsan_common.cpp`,
* `ClassifyAllChunks`); the D GC's mmap'd pools are not chunks, so
* pointers stored in GC memory are invisible to the scan.
* 3. Q3 `new ubyte[4004]` dropped -> NOT reported: GC
* allocations don't come from the intercepted `malloc`, so true GC
* leaks are invisible to LSan.
* 4. Q4 `malloc(5005)` referenced from a `__gshared` global -> silent:
* the root scan does cover D's `.data`/`.bss`.
*
* Also demonstrated, correcting a natural assumption: `detect_leaks=0`
* disables the MANUAL check entry points too (`__lsan_do_leak_check` is
* gated on the flag, compiler-rt `lsan_common.cpp:1193-1197`) — the
* composable recipe for per-test checking is `leak_check_at_exit=0` plus
* repeated `__lsan_do_recoverable_leak_check()`. Standalone LSan exits with
* code 23 on leaks (`lsan.cpp:61`).
*
* No `LDC_LeakSanitizer` version identifier exists (LDC predefines them only
* for address/memory/thread — `driver/main.cpp:1030-1041` @ v1.41.0), so
* this probe detects instrumentation at RUNTIME via
* `dlsym(RTLD_DEFAULT, "__lsan_do_leak_check")`; all `__lsan_*` calls go
* through the resolved pointers so uninstrumented builds still link.
*
* Companion to docs/research/sanitizers/asan.md
* § "LeakSanitizer and the D GC".
*
* Run with: dub run --single lsan-gc-interplay.d
*
* Environment recorded: Linux 6.18.26, AMD Ryzen 9 7940HX, LDC 1.41.0
* (LLVM 18.1.8), GCC 15.2 `liblsan.so.0` runtime via LDC's gcc link fallback.
*
* Portability: uninstrumented builds (DMD; the dflag is LDC-gated) find no
* `__lsan_*` symbols, print a `SKIP:` line and exit 0.
*/
module (module) sanitizers_lsan_gc_interplayStandalone LeakSanitizer vs the D garbage collector, four quadrants — the
blind spots a --sanitize=leak runner mode must document:
Q1 malloc(1001), unreachable -> reported (true leak).
Q2 malloc(2002) referenced ONLY from a GC array -> reported anyway:
a FALSE POSITIVE. LSan's flood fill follows pointers only through its
own allocator's chunks (compiler-rt lsan_common.cpp,
ClassifyAllChunks); the D GC's mmap'd pools are not chunks, so
pointers stored in GC memory are invisible to the scan.
Q3 new ubyte[4004] dropped -> NOT reported: GC
allocations don't come from the intercepted malloc, so true GC
leaks are invisible to LSan.
Q4 malloc(5005) referenced from a __gshared global -> silent:
the root scan does cover D's .data/.bss.
Also demonstrated, correcting a natural assumption: detect_leaks=0
disables the MANUAL check entry points too (__lsan_do_leak_check is
gated on the flag, compiler-rt lsan_common.cpp:1193-1197) — the
composable recipe for per-test checking is leak_check_at_exit=0 plus
repeated __lsan_do_recoverable_leak_check(). Standalone LSan exits with
code 23 on leaks (lsan.cpp:61).
No LDC_LeakSanitizer version identifier exists (LDC predefines them only
for address/memory/thread — driver/main.cpp:1030-1041 @ v1.41.0), so
this probe detects instrumentation at RUNTIME via
dlsym(RTLD_DEFAULT, "__lsan_do_leak_check"); all __lsan_* calls go
through the resolved pointers so uninstrumented builds still link.
Companion to docs/research/sanitizers/asan.md
§ "LeakSanitizer and the D GC".
Run with: dub run --single lsan-gc-interplay.d
Environment recorded: Linux 6.18.26, AMD Ryzen 9 7940HX, LDC 1.41.0
(LLVM 18.1.8), GCC 15.2 liblsan.so.0 runtime via LDC's gcc link fallback.
Portability
uninstrumented builds (DMD; the dflag is LDC-gated) find no
__lsan_* symbols, print a SKIP: line and exit 0.
sanitizers_lsan_gc_interplay;
version (linuxlinux)
{
import (package) stdstd.(module) std.stdioCategory Symbols File handles _popen File isFileHandle openNetwork stderr stdin stdout Reading chunks lines readf readfln readln Writing toFile write writef writefln writeln Misc KeepTerminator LockType StdioException
Standard I/O functions that extend core.stdc.stdio. core.stdc.stdio
is publically imported when importing std.stdio.
There are three layers of I/O:
The lowest layer is the operating system layer. The two main schemes are Windows and Posix.
C's stdio.h which unifies the two operating system schemes.
std.stdio, this module, unifies the various stdio.h implementations into
a high level package for D programs.
Source
std/stdio.d
stdio : (alias template) sanitizers_lsan_gc_interplay.writefln = std.stdio.writefln(alias fmt, A...)(A args) if (isSomeString!(typeof(fmt)))Equivalent to writef(fmt, args, '\n').
writefln;
enum (constant) string sanitizers_lsan_gc_interplay.childEnvVar = "SANITIZERS_PROBE_CHILD"childEnvVar = "SANITIZERS_PROBE_CHILD";
alias (alias) sanitizers_lsan_gc_interplay.FatalCheckFn = extern (C) void function()FatalCheckFn = extern (C) void function();
alias (alias) sanitizers_lsan_gc_interplay.RecoverableCheckFn = extern (C) int function()RecoverableCheckFn = extern (C) int function();
/// Runtime instrumentation detection: resolve the LSan entry points via
/// `dlsym` so an uninstrumented binary still links (and SKIPs).
bool bool sanitizers_lsan_gc_interplay.lsanLive(out extern (C) void function() fatal, out extern (C) int function() recoverable)Runtime instrumentation detection: resolve the LSan entry points via
dlsym so an uninstrumented binary still links (and SKIPs).
lsanLive(out (alias) sanitizers_lsan_gc_interplay.FatalCheckFn = extern (C) void function()FatalCheckFn (parameter) extern (C) void function() fatalfatal, out (alias) sanitizers_lsan_gc_interplay.RecoverableCheckFn = extern (C) int function()RecoverableCheckFn (parameter) extern (C) int function() recoverablerecoverable)
{
import (package) corecore.(package) core.syssys.(package) core.sys.linuxlinux.(module) core.sys.linux.dlfcnD header file for GNU/Linux
dlfcn : (alias) dlsym = void* core.sys.posix.dlfcn.dlsym(void*, scope const(char*)) nothrow @nogcdlsym, (alias constant) RTLD_DEFAULT = void* core.sys.linux.dlfcn.RTLD_DEFAULT = cast(void*)cast(size_t)0LURTLD_DEFAULT;
(parameter) extern (C) void function() fatalfatal = cast((alias) sanitizers_lsan_gc_interplay.FatalCheckFn = extern (C) void function()FatalCheckFn) void* core.sys.posix.dlfcn.dlsym(void*, scope const(char*)) nothrow @nogcdlsym((constant) void* core.sys.linux.dlfcn.RTLD_DEFAULT = cast(void*)cast(size_t)0LURTLD_DEFAULT, "__lsan_do_leak_check");
(parameter) extern (C) int function() recoverablerecoverable = cast((alias) sanitizers_lsan_gc_interplay.RecoverableCheckFn = extern (C) int function()RecoverableCheckFn) void* core.sys.posix.dlfcn.dlsym(void*, scope const(char*)) nothrow @nogcdlsym((constant) void* core.sys.linux.dlfcn.RTLD_DEFAULT = cast(void*)cast(size_t)0LURTLD_DEFAULT,
"__lsan_do_recoverable_leak_check");
return (parameter) extern (C) void function() fatalfatal !is null && (parameter) extern (C) int function() recoverablerecoverable !is null;
}
__gshared void*[] (__gshared global) void*[] sanitizers_lsan_gc_interplay.gcKeeperkeeps the Q2 GC array alive via a data root
gcKeeper; /// keeps the Q2 GC array alive via a data root
__gshared void* (__gshared global) void* sanitizers_lsan_gc_interplay.mallocKeeperQ4
a reachable malloc block
mallocKeeper; /// Q4: a reachable malloc block
void void sanitizers_lsan_gc_interplay.makeLeaks()makeLeaks()
{
import (package) corecore.(package) core.stdcstdc.(module) core.stdc.stdlibD header file for C99.
pubs.opengroup.org/onlinepubs/009695399/basedefs/stdlib.h.html, stdlib.h
Source
core/stdc/stdlib.d
stdlib : (alias) malloc = void* core.stdc.stdlib.malloc(ulong size) nothrow @nogcmalloc;
void* (local variable) void* q1q1 = void* core.stdc.stdlib.malloc(ulong size) nothrow @nogcmalloc(1001); // Q1: unreachable malloc -> true leak
(local variable) void* q1q1 = null;
auto (local variable) void*[] arrarr = new void*[4]; // a GC allocation (mmap'd pool)
(local variable) void*[] arrarr[0] = void* core.stdc.stdlib.malloc(ulong size) nothrow @nogcmalloc(2002); // Q2: only reference lives in GC memory
(__gshared global) void*[] sanitizers_lsan_gc_interplay.gcKeeperkeeps the Q2 GC array alive via a data root
gcKeeper = (local variable) void*[] arrarr;
auto (local variable) ubyte[] q3q3 = new ubyte[4004]; // Q3: dropped GC allocation
(local variable) ubyte[] q3q3 = null;
(__gshared global) void* sanitizers_lsan_gc_interplay.mallocKeeperQ4
a reachable malloc block
mallocKeeper = void* core.stdc.stdlib.malloc(ulong size) nothrow @nogcmalloc(5005); // Q4: reachable from .data — no leak
}
/// Scrub a few KB of stack so dead pointer copies from `makeLeaks` don't
/// make Q1/Q2 spuriously reachable to LSan's conservative scan.
void void sanitizers_lsan_gc_interplay.scrubStack()Scrub a few KB of stack so dead pointer copies from makeLeaks don't
make Q1/Q2 spuriously reachable to LSan's conservative scan.
scrubStack()
{
import (package) corecore.(package) core.stdcstdc.(module) core.stdc.stdioD header file for C99 <stdio.h>
pubs.opengroup.org/onlinepubs/009695399/basedefs/stdio.h.html, stdio.h
Source
core/stdc/stdio.d
stdio : (alias) printf = int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogcprintf;
ubyte[8192] (local variable) ubyte[8192] padpad = 0;
int core.stdc.stdio.printf(scope const(char*) format, scope const ...) nothrow @nogcprintf("", (local variable) ubyte[8192] padpad.(constant) ubyte* ubyte[8192].ptr = &padptr);
}
void void sanitizers_lsan_gc_interplay.childDemo(extern (C) void function() fatal, extern (C) int function() recoverable)childDemo((alias) sanitizers_lsan_gc_interplay.FatalCheckFn = extern (C) void function()FatalCheckFn (parameter) extern (C) void function() fatalfatal, (alias) sanitizers_lsan_gc_interplay.RecoverableCheckFn = extern (C) int function()RecoverableCheckFn (parameter) extern (C) int function() recoverablerecoverable)
{
import (package) corecore.(package) core.stdcstdc.(module) core.stdc.stdioD header file for C99 <stdio.h>
pubs.opengroup.org/onlinepubs/009695399/basedefs/stdio.h.html, stdio.h
Source
core/stdc/stdio.d
stdio : (alias) fprintf = int core.stdc.stdio.fprintf(shared(core.stdc.stdio._IO_FILE)* stream, scope const(char*) format, scope const ...) nothrow @nogcfprintf, (alias shared global) stderr = shared(core.stdc.stdio._IO_FILE*) core.stdc.stdio.stderrstderr;
void sanitizers_lsan_gc_interplay.makeLeaks()makeLeaks();
void sanitizers_lsan_gc_interplay.scrubStack()Scrub a few KB of stack so dead pointer copies from makeLeaks don't
make Q1/Q2 spuriously reachable to LSan's conservative scan.
scrubStack();
const (local variable) const(int) nn = (parameter) extern (C) int function() recoverablerecoverable(); // prints a report, does NOT die
int core.stdc.stdio.fprintf(shared(core.stdc.stdio._IO_FILE)* stream, scope const(char*) format, scope const ...) nothrow @nogcfprintf((shared global) shared(core.stdc.stdio._IO_FILE*) core.stdc.stdio.stderrstderr, "recoverable returned %d\n", (local variable) const(int) nn);
(parameter) extern (C) void function() fatalfatal(); // dies with exit code 23 when leaks were found ...
int core.stdc.stdio.fprintf(shared(core.stdc.stdio._IO_FILE)* stream, scope const(char*) format, scope const ...) nothrow @nogcfprintf((shared global) shared(core.stdc.stdio._IO_FILE*) core.stdc.stdio.stderrstderr, "survived both manual checks\n"); // ... else reached
}
int int sanitizers_lsan_gc_interplay.spawnChild(string[string] extraEnv, out string output)spawnChild((alias) object.string = stringstring[(alias) object.string = stringstring] (parameter) string[string] extraEnvextraEnv, out (alias) object.string = stringstring (parameter) string outputoutput)
{
import (package) stdstd.(module) std.arrayFunctions and types that manipulate built-in arrays and associative arrays.
This module provides all kinds of functions to create, manipulate or convert arrays:
Function Name Description
| array |
Returns a copy of the input in a newly allocated dynamic array.
|
| appender |
Returns a new Appender or RefAppender initialized with a given array.
|
| assocArray |
Returns a newly allocated associative array from a range/ranges of keys and values.
|
| byPair |
Construct a range iterating over an associative array by key/value tuples.
|
| insertInPlace |
Inserts into an existing array at a given position.
|
| join |
Concatenates a range of ranges into one array.
|
| minimallyInitializedArray |
Returns a new array of type T.
|
| replace |
Returns a new array with all occurrences of a certain subrange replaced.
|
| replaceFirst |
Returns a new array with the first occurrence of a certain subrange replaced.
|
| replaceInPlace |
Replaces all occurrences of a certain subrange and puts the result into a given array.
|
| replaceInto |
Replaces all occurrences of a certain subrange and puts the result into an output range.
|
| replaceLast |
Returns a new array with the last occurrence of a certain subrange replaced.
|
| replaceSlice |
Returns a new array with a given slice replaced.
|
| replicate |
Creates a new array out of several copies of an input array or range.
|
| sameHead |
Checks if the initial segments of two arrays refer to the same
place in memory.
|
| sameTail |
Checks if the final segments of two arrays refer to the same place
in memory.
|
| split |
Eagerly split a range or string into an array.
|
| staticArray |
Creates a new static array from given data.
|
| uninitializedArray |
Returns a new array of type T without initializing its elements.
|
Source
std/array.d
array : (alias template) array = std.array.array(Range)(Range r) if (isIterable!Range && !isAutodecodableString!Range && !isInfinite!Range)Allocates an array and initializes it with copies of the elements
of range r.
Narrow strings are handled as follows:
If autodecoding is turned on (default), then they are handled as a separate overload.
If autodecoding is turned off, then this is equivalent to duplicating the array.
Params:
r = range (or aggregate with opApply function) whose elements are copied into the allocated array
Returns:
allocated and initialized array
array, (alias template) join = std.array.join(RoR, R)(RoR ror, R sep) if (isInputRange!RoR && isInputRange!(Unqual!(ElementType!RoR)) && isInputRange!R && (is(immutable(ElementType!(ElementType!RoR)) == immutable(ElementType!R)) || isSomeChar!(ElementType!(ElementType!RoR)) && isSomeChar!(ElementType!R)))Eagerly concatenates all of the ranges in ror together (with the GC)
into one array using sep as the separator if present.
Params:
ror = An $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
of input ranges
sep = An input range, or a single element, to join the ranges on
Returns:
An array of elements
See_Also:
For a lazy version, see $(REF joiner, std,algorithm,iteration)
join;
import (package) stdstd.(module) std.fileUtilities for manipulating files and scanning directories. Functions
in this module handle files as a unit, e.g., read or write one file
at a time. For opening files and manipulating them via handles refer
to module std.stdio.
Category Functions General exists isDir isFile isSymlink rename thisExePath Directories chdir dirEntries getcwd mkdir mkdirRecurse rmdir rmdirRecurse tempDir Files append copy read readText remove slurp write Symlinks symlink readLink Attributes attrIsDir attrIsFile attrIsSymlink getAttributes getLinkAttributes getSize setAttributes Timestamp getTimes getTimesWin setTimes timeLastModified timeLastAccessed timeStatusChanged Other DirEntry FileException PreserveAttributes SpanMode getAvailableDiskSpace
Source
std/file.d
file : (alias) thisExePath = string std.file.thisExePath() @trustedReturns the full path of the current executable.
Returns:
The path of the executable as a string.
Throws:
$(REF1 Exception, object)
thisExePath;
import (package) stdstd.(module) std.processFunctions for starting and interacting with other processes, and for
working with the current process' execution environment.
Process handling
`spawnProcess` spawns a new `process`, optionally assigning it an
arbitrary set of standard input, output, and error streams.
The function returns immediately, leaving the child process to execute
in parallel with its parent. All other functions in this module that
spawn processes are built around spawnProcess.
`wait` makes the parent `process` wait for a child `process` to
terminate. In general one should always do this, to avoid
child processes becoming "zombies" when the parent process exits.
Scope guards are perfect for this – see the spawnProcess
documentation for examples. tryWait is similar to wait,
but does not block if the process has not yet terminated.
`pipeProcess` also spawns a child `process` which runs
in parallel with its parent. However, instead of taking
arbitrary streams, it automatically creates a set of
pipes that allow the parent to communicate with the child
through the child's standard input, output, and/or error streams.
This function corresponds roughly to C's popen function.
`execute` starts a new `process` and waits for it
to complete before returning. Additionally, it captures
the process' standard output and error streams and returns
the output of these as a string.
`spawnShell`, `pipeShell` and `executeShell` work like
spawnProcess, pipeProcess and execute, respectively,
except that they take a single command string and run it through
the current user's default command interpreter.
executeShell corresponds roughly to C's system function.
`kill` attempts to terminate a running `process`.
The following table compactly summarises the different process creation
functions and how they relate to each other:
Runs program directly
Runs shell command Low-level process creation spawnProcess spawnShell Automatic input/output redirection using pipes pipeProcess pipeShell Execute and wait for completion, collect output execute executeShell
Other functionality
`pipe` is used to create unidirectional pipes.
`environment` is an interface through which the current `process`'
environment variables can be read and manipulated.
`escapeShellCommand` and `escapeShellFileName` are useful
for constructing shell command lines in a portable way.
Source
std/process.d
Note
Most of the functionality in this module is not available on iOS, tvOS
and watchOS. The only functions available on those platforms are:
environment, thisProcessID and thisThreadID.
process : (alias) pipeProcess = std.process.ProcessPipes std.process.pipeProcess(scope const(char[])[] args, std.process.Redirect redirect = Redirect.all, const(string[string]) env = cast(const(string[string]))null, std.process.Config config = Config(Flags.none, null, null), scope const(char)[] workDir = null) @safeStarts a new process, creating pipes to redirect its standard
input, output and/or error streams.
pipeProcess and pipeShell are convenient wrappers around
$(LREF spawnProcess) and $(LREF spawnShell), respectively, and
automate the task of redirecting one or more of the child process'
standard streams through pipes. Like the functions they wrap,
these functions return immediately, leaving the child process to
execute in parallel with the invoking process. It is recommended
to always call $(LREF wait) on the returned $(LREF ProcessPipes.pid),
as detailed in the documentation for wait.
The args/program/command, env and config
parameters are forwarded straight to the underlying spawn functions,
and we refer to their documentation for details.
Params:
args = An array which contains the program name as the zeroth element
and any command-line arguments in the following elements.
(See $(LREF spawnProcess) for details.)
program = The program name, $(I without) command-line arguments.
(See $(LREF spawnProcess) for details.)
command = A shell command which is passed verbatim to the command
interpreter. (See $(LREF spawnShell) for details.)
redirect = Flags that determine which streams are redirected, and
how. See $(LREF Redirect) for an overview of available
flags.
env = Additional environment variables for the child process.
(See $(LREF spawnProcess) for details.)
config = Flags that control process creation. See $(LREF Config)
for an overview of available flags, and note that the
`retainStd...` flags have no effect in this function.
workDir = The working directory for the new process.
By default the child process inherits the parent's working
directory.
shellPath = The path to the shell to use to run the specified program.
By default this is $(LREF nativeShell).
Returns:
A $(LREF ProcessPipes) object which contains $(REF File, std,stdio)
handles that communicate with the redirected streams of the child
process, along with a $(LREF Pid) object that corresponds to the
spawned process.
Throws:
$(LREF ProcessException) on failure to start the process.$(BR)
$(REF StdioException, std,stdio) on failure to redirect any of the streams.$(BR)
Example:
// my_application writes to stdout and might write to stderr
auto pipes = pipeProcess("my_application", Redirect.stdout | Redirect.stderr);
scope(exit) wait(pipes.pid);
// Store lines of output.
string[] output;
foreach (line; pipes.stdout.byLine) output ~= line.idup;
// Store lines of errors.
string[] errors;
foreach (line; pipes.stderr.byLine) errors ~= line.idup;
// sendmail expects to read from stdin
pipes = pipeProcess("/usr/bin/sendmail", "-t", Redirect.stdin);
pipes.stdin.writeln("To: you");
pipes.stdin.writeln("From: me");
pipes.stdin.writeln("Subject: dlang");
pipes.stdin.writeln("");
pipes.stdin.writeln(message);
// a single period tells sendmail we are finished
pipes.stdin.writeln(".");
// but at this point sendmail might not see it, we need to flush
pipes.stdin.flush();
// sendmail happens to exit on ".", but some you have to close the file:
pipes.stdin.close();
// otherwise this wait will wait forever
wait(pipes.pid);
---
pipeProcess, (enum) std.process.RedirectFlags that can be passed to pipeProcess and pipeShell
to specify which of the child process' standard streams are redirected.
Use bitwise OR to combine flags.
Redirect, (alias) wait = int std.process.wait(std.process.Pid pid) @safeWaits for the process associated with pid to terminate, and returns
its exit status.
In general one should always _wait for child processes to terminate
before exiting the parent process unless the process was spawned as detached
(that was spawned with Config.detached flag).
Otherwise, they may become "$(HTTP en.wikipedia.org/wiki/Zombie_process,zombies)"
– processes that are defunct, yet still occupy a slot in the OS process table.
You should not and must not wait for detached processes, since you don't own them.
If the process has already terminated, this function returns directly.
The exit code is cached, so that if wait() is called multiple times on
the same $(LREF Pid) it will always return the same value.
POSIX_specific:
If the process is terminated by a signal, this function returns a
negative number whose absolute value is the signal number.
Since POSIX restricts normal exit codes to the range 0-255, a
negative return value will always indicate termination by signal.
Signal codes are defined in the core.sys.posix.signal module
(which corresponds to the signal.h POSIX header).
Throws:
$(LREF ProcessException) on failure or on attempt to wait for detached process.
Example:
See the $(LREF spawnProcess) documentation.
See_also:
$(LREF tryWait), for a non-blocking function.
wait;
auto (local variable) std.process.ProcessPipes pp = std.process.ProcessPipes std.process.pipeProcess(scope const(char[])[] args, std.process.Redirect redirect = Redirect.all, const(string[string]) env = cast(const(string[string]))null, std.process.Config config = Config(Flags.none, null, null), scope const(char)[] workDir = null) @safeStarts a new process, creating pipes to redirect its standard
input, output and/or error streams.
pipeProcess and pipeShell are convenient wrappers around
spawnProcess and spawnShell, respectively, and
automate the task of redirecting one or more of the child process'
standard streams through pipes. Like the functions they wrap,
these functions return immediately, leaving the child process to
execute in parallel with the invoking process. It is recommended
to always call wait on the returned ProcessPipes.pid,
as detailed in the documentation for wait.
The args/program/command, env and config
parameters are forwarded straight to the underlying spawn functions,
and we refer to their documentation for details.
Example
// my_application writes to stdout and might write to stderr
auto pipes = pipeProcess("my_application", Redirect.stdout | Redirect.stderr);
scope(exit) wait(pipes.pid);
// Store lines of output.
string[] output;
foreach (line; pipes.stdout.byLine) output ~= line.idup;
// Store lines of errors.
string[] errors;
foreach (line; pipes.stderr.byLine) errors ~= line.idup;
// sendmail expects to read from stdin
pipes = pipeProcess(["/usr/bin/sendmail", "-t"], Redirect.stdin);
pipes.stdin.writeln("To: you");
pipes.stdin.writeln("From: me");
pipes.stdin.writeln("Subject: dlang");
pipes.stdin.writeln("");
pipes.stdin.writeln(message);
// a single period tells sendmail we are finished
pipes.stdin.writeln(".");
// but at this point sendmail might not see it, we need to flush
pipes.stdin.flush();
// sendmail happens to exit on ".", but some you have to close the file:
pipes.stdin.close();
// otherwise this wait will wait forever
wait(pipes.pid);
pipeProcess([string std.file.thisExePath() @trustedReturns the full path of the current executable.
Examples
import std.path : isAbsolute;
auto path = thisExePath();
assert(path.exists);
assert(path.isAbsolute);
assert(path.isFile);
thisExePath],
(enum) std.process.RedirectFlags that can be passed to pipeProcess and pipeShell
to specify which of the child process' standard streams are redirected.
Use bitwise OR to combine flags.
Redirect.(enum value) std.process.Redirect.stdout = 2Redirect the standard input, output or error streams, respectively.
stdout | (enum) std.process.RedirectFlags that can be passed to pipeProcess and pipeShell
to specify which of the child process' standard streams are redirected.
Use bitwise OR to combine flags.
Redirect.(enum value) std.process.Redirect.stderrToStdout = 8Redirect the standard error stream into the standard output stream.
This can not be combined with Redirect.stderr.
stderrToStdout, (parameter) string[string] extraEnvextraEnv);
(parameter) string outputoutput = (local variable) std.process.ProcessPipes pp.std.stdio.File std.process.ProcessPipes.stdout() nothrow @property @safeAn File that allows reading from the child process'
standard output stream.
stdout.std.stdio.File.ByLineCopy!(immutable(char), char) std.stdio.File.byLineCopy!(char, immutable(char))(std.typecons.Flag!"keepTerminator" keepTerminator = Flag.no, char terminator = '\n') @systemReturns an input range
set up to read from the file handle one line
at a time. Each line will be newly allocated. front will cache
its value to allow repeated calls without unnecessary allocations.
Note
Due to caching byLineCopy can be more memory-efficient than
File.byLine.map!idup.
The element type for the range will be Char[]. Range
primitives may throw StdioException on I/O error.
Example
import std.algorithm, std.array, std.stdio;
// Print sorted lines of a file.
void main()
{
auto sortedLines = File("file.txt") // Open for reading
.byLineCopy() // Read persistent lines
.array() // into an array
.sort(); // then sort them
foreach (line; sortedLines)
writeln(line);
}
byLineCopy.string[] std.array.array!(std.stdio.File.ByLineCopy!(immutable(char), char))(std.stdio.File.ByLineCopy!(immutable(char), char) r) @systemAllocates an array and initializes it with copies of the elements
of range r.
Narrow strings are handled as follows:
If autodecoding is turned on (default), then they are handled as a separate overload.
If autodecoding is turned off, then this is equivalent to duplicating the array.
array.string std.array.join!(string[], string)(string[] ror, string sep) pure nothrow @safeEagerly concatenates all of the ranges in ror together (with the GC)
into one array using sep as the separator if present.
join("\n");
return int std.process.wait(std.process.Pid pid) @safeWaits for the process associated with pid to terminate, and returns
its exit status.
In general one should always wait for child processes to terminate
before exiting the parent process unless the process was spawned as detached
(that was spawned with Config.detached flag).
Otherwise, they may become "zombies"
– processes that are defunct, yet still occupy a slot in the OS process table.
You should not and must not wait for detached processes, since you don't own them.
If the process has already terminated, this function returns directly.
The exit code is cached, so that if wait() is called multiple times on
the same Pid it will always return the same value.
POSIX specific
If the process is terminated by a signal, this function returns a
negative number whose absolute value is the signal number.
Since POSIX restricts normal exit codes to the range 0-255, a
negative return value will always indicate termination by signal.
Signal codes are defined in the core.sys.posix.signal module
(which corresponds to the signal.h POSIX header).
Example
See the spawnProcess documentation.
wait((local variable) std.process.ProcessPipes pp.std.process.Pid std.process.ProcessPipes.pid() nothrow @property @safeThe Pid of the child process.
pid);
}
int int sanitizers_lsan_gc_interplay.run()run()
{
import (package) stdstd.(package) std.algorithmalgorithm.(module) std.algorithm.searchingThis is a submodule of std.algorithm.
It contains generic searching algorithms.
Function Name Description all all!"a > 0"([1, 2, 3, 4]) returns true because all elements are positive any any!"a > 0"([1, 2, -3, -4]) returns true because at least one element is positive balancedParens balancedParens("((1 + 1) / 2)", '(', ')') returns true because the string has balanced parentheses. boyerMooreFinder find("hello world", boyerMooreFinder("or")) returns "orld" using the Boyer-Moore algorithm. canFind canFind("hello world", "or") returns true. count Counts all elements or elements matching a predicate, specific element or sub-range.
count([1, 2, 1]) returns 3,
count([1, 2, 1], 1) returns 2 and
count!"a < 0"([1, -3, 0]) returns 1. |
| countUntil | countUntil(a, b) returns the number of steps taken in a to reach b; for example, countUntil("hello!", "o") returns 4. |
| commonPrefix | commonPrefix("parakeet", "parachute") returns "para". |
| endsWith | endsWith("rocks", "ks") returns true. |
| extrema | extrema([2, 1, 3, 5, 4]) returns [1, 5]. |
| find | find("hello world", "or") returns "orld" using linear search. (For binary search refer to SortedRange.) |
| findAdjacent | findAdjacent([1, 2, 3, 3, 4]) returns the subrange starting with two equal adjacent elements, i.e. [3, 3, 4]. |
| findAmong | findAmong("abcd", "qcx") returns "cd" because 'c' is among "qcx". |
| findSkip | If a = "abcde", then findSkip(a, "x") returns false and leaves a unchanged, whereas findSkip(a, "c") advances a to "de" and returns true. |
| findSplit | findSplit("abcdefg", "de") returns a tuple of three ranges "abc", "de", and "fg". |
| findSplitAfter | findSplitAfter("abcdefg", "de") returns a tuple of two ranges "abcde" and "fg". |
| findSplitBefore | findSplitBefore("abcdefg", "de") returns a tuple of two ranges "abc" and "defg". |
| minCount | minCount([2, 1, 1, 4, 1]) returns tuple(1, 3). |
| maxCount | maxCount([2, 4, 1, 4, 1]) returns tuple(4, 2). |
| minElement | Selects the minimal element of a range. minElement([3, 4, 1, 2]) returns 1. |
| maxElement | Selects the maximal element of a range. maxElement([3, 4, 1, 2]) returns 4. |
| minIndex | Index of the minimal element of a range. minIndex([3, 4, 1, 2]) returns 2. |
| maxIndex | Index of the maximal element of a range. maxIndex([3, 4, 1, 2]) returns 1. |
| minPos | minPos([2, 3, 1, 3, 4, 1]) returns the subrange [1, 3, 4, 1], i.e., positions the range at the first occurrence of its minimal element. |
| maxPos | maxPos([2, 3, 1, 3, 4, 1]) returns the subrange [4, 1], i.e., positions the range at the first occurrence of its maximal element. |
| skipOver | Assume a = "blah". Then skipOver(a, "bi") leaves a unchanged and returns false, whereas skipOver(a, "bl") advances a to refer to "ah" and returns true. |
| startsWith | startsWith("hello, world", "hello") returns true. |
| until | Lazily iterates a range until a specific value is found. |
Source
std/algorithm/searching.d
searching : (alias template) canFind = std.algorithm.searching.canFind(alias pred = "a == b")Convenience function. Like find, but only returns whether or not the search
was successful.
For more information about pred see $(LREF find).
See_Also:
$(REF among, std,algorithm,comparison) for checking a value against multiple arguments.
canFind;
import (package) stdstd.(module) std.processFunctions for starting and interacting with other processes, and for
working with the current process' execution environment.
Process handling
`spawnProcess` spawns a new `process`, optionally assigning it an
arbitrary set of standard input, output, and error streams.
The function returns immediately, leaving the child process to execute
in parallel with its parent. All other functions in this module that
spawn processes are built around spawnProcess.
`wait` makes the parent `process` wait for a child `process` to
terminate. In general one should always do this, to avoid
child processes becoming "zombies" when the parent process exits.
Scope guards are perfect for this – see the spawnProcess
documentation for examples. tryWait is similar to wait,
but does not block if the process has not yet terminated.
`pipeProcess` also spawns a child `process` which runs
in parallel with its parent. However, instead of taking
arbitrary streams, it automatically creates a set of
pipes that allow the parent to communicate with the child
through the child's standard input, output, and/or error streams.
This function corresponds roughly to C's popen function.
`execute` starts a new `process` and waits for it
to complete before returning. Additionally, it captures
the process' standard output and error streams and returns
the output of these as a string.
`spawnShell`, `pipeShell` and `executeShell` work like
spawnProcess, pipeProcess and execute, respectively,
except that they take a single command string and run it through
the current user's default command interpreter.
executeShell corresponds roughly to C's system function.
`kill` attempts to terminate a running `process`.
The following table compactly summarises the different process creation
functions and how they relate to each other:
Runs program directly
Runs shell command Low-level process creation spawnProcess spawnShell Automatic input/output redirection using pipes pipeProcess pipeShell Execute and wait for completion, collect output execute executeShell
Other functionality
`pipe` is used to create unidirectional pipes.
`environment` is an interface through which the current `process`'
environment variables can be read and manipulated.
`escapeShellCommand` and `escapeShellFileName` are useful
for constructing shell command lines in a portable way.
Source
std/process.d
Note
Most of the functionality in this module is not available on iOS, tvOS
and watchOS. The only functions available on those platforms are:
environment, thisProcessID and thisThreadID.
process : (class) std.process.environmentManipulates environment variables using an associative-array-like
interface.
This class contains only static methods, and cannot be instantiated.
See below for examples of use.
environment;
(alias) sanitizers_lsan_gc_interplay.FatalCheckFn = extern (C) void function()FatalCheckFn (local variable) extern (C) void function() fatalfatal;
(alias) sanitizers_lsan_gc_interplay.RecoverableCheckFn = extern (C) int function()RecoverableCheckFn (local variable) extern (C) int function() recoverablerecoverable;
if (!bool sanitizers_lsan_gc_interplay.lsanLive(out extern (C) void function() fatal, out extern (C) int function() recoverable)Runtime instrumentation detection: resolve the LSan entry points via
dlsym so an uninstrumented binary still links (and SKIPs).
lsanLive((local variable) extern (C) void function() fatalfatal, (local variable) extern (C) int function() recoverablerecoverable))
{
void std.stdio.writefln!char(in char[] fmt) @safeEquivalent to writef(fmt, args, '\n').
writefln("SKIP: no __lsan_* entry points in this binary "
~ "(built without -fsanitize=leak; e.g. a DMD build)");
return 0;
}
if ((class) std.process.environmentManipulates environment variables using an associative-array-like
interface.
This class contains only static methods, and cannot be instantiated.
See below for examples of use.
environment.string std.process.environment.get(scope const(char)[] name, string defaultValue = null) @safeRetrieves the value of the environment variable with the given name,
or a default value if the variable doesn't exist.
Unlike environment.opIndex, this function never throws on Posix.
auto sh = environment.get("SHELL", "/bin/sh");
This function is also useful in checking for the existence of an
environment variable.
auto myVar = environment.get("MYVAR");
if (myVar is null)
{
// Environment variable doesn't exist.
// Note that we have to use 'is' for the comparison, since
// myVar == null is also true if the variable exists but is
// empty.
}
get((constant) string sanitizers_lsan_gc_interplay.childEnvVar = "SANITIZERS_PROBE_CHILD"childEnvVar) == "leaks")
{
void sanitizers_lsan_gc_interplay.childDemo(extern (C) void function() fatal, extern (C) int function() recoverable)childDemo((local variable) extern (C) void function() fatalfatal, (local variable) extern (C) int function() recoverablerecoverable);
return 0;
}
void void sanitizers_lsan_gc_interplay.run.check(bool cond, string what, string output) @systemcheck(bool (parameter) bool condcond, (alias) object.string = stringstring (parameter) string whatwhat, (alias) object.string = stringstring (parameter) string outputoutput)
{
if (!(parameter) bool condcond)
{
void std.stdio.writefln!(char, string, string)(in char[] fmt, string __param_1, string __param_2) @safeEquivalent to writef(fmt, args, '\n').
writefln("FAIL: %s\n--- child output ---\n%s", (parameter) string whatwhat, (parameter) string outputoutput);
import (package) corecore.(package) core.stdcstdc.(module) core.stdc.stdlibD header file for C99.
pubs.opengroup.org/onlinepubs/009695399/basedefs/stdlib.h.html, stdlib.h
Source
core/stdc/stdlib.d
stdlib : (alias) exit = noreturn core.stdc.stdlib.exit(int status) nothrow @nogcexit;
noreturn core.stdc.stdlib.exit(int status) nothrow @nogcexit(1);
}
}
// Child A: default options — quadrants + manual checks.
(alias) object.string = stringstring (local variable) string outAoutA;
const (local variable) const(int) codeAcodeA = int sanitizers_lsan_gc_interplay.spawnChild(string[string] extraEnv, out string output)spawnChild([(constant) string sanitizers_lsan_gc_interplay.childEnvVar = "SANITIZERS_PROBE_CHILD"childEnvVar: "leaks"], (local variable) string outAoutA);
void sanitizers_lsan_gc_interplay.run.check(bool cond, string what, string output) @systemcheck((local variable) const(int) codeAcodeA == 23, "leaking child should exit 23 (standalone LSan)",
(local variable) string outAoutA);
void sanitizers_lsan_gc_interplay.run.check(bool cond, string what, string output) @systemcheck((local variable) string outAoutA.bool std.algorithm.searching.canFind!().canFind!(string, string)(string haystack, scope string needle) pure nothrow @nogc @safeConvenience function. Like find, but only returns whether or not the search
was successful.
For more information about pred see find.
Examples
const arr = [0, 1, 2, 3];
assert(canFind(arr, 2));
assert(!canFind(arr, 4));
// find one of several needles
assert(arr.canFind(3, 2));
assert(arr.canFind(3, 2) == 2); // second needle found
assert(arr.canFind([1, 3], 2) == 2);
assert(canFind(arr, [1, 2], [2, 3]));
assert(canFind(arr, [1, 2], [2, 3]) == 1);
assert(canFind(arr, [1, 7], [2, 3]));
assert(canFind(arr, [1, 7], [2, 3]) == 2);
assert(!canFind(arr, [1, 3], [2, 4]));
assert(canFind(arr, [1, 3], [2, 4]) == 0);
Example using a custom predicate.
Note that the needle appears as the second argument of the predicate.
auto words = [
"apple",
"beeswax",
"cardboard"
];
assert(!canFind(words, "bees"));
assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees"));
Search for multiple items in an array of items (search for needles in an array of haystacks)
string s1 = "aaa111aaa";
string s2 = "aaa222aaa";
string s3 = "aaa333aaa";
string s4 = "aaa444aaa";
const hay = [s1, s2, s3, s4];
assert(hay.canFind!(e => e.canFind("111", "222")));
canFind("LeakSanitizer: detected memory leaks"), "child A "
~ "should report leaks", (local variable) string outAoutA);
void sanitizers_lsan_gc_interplay.run.check(bool cond, string what, string output) @systemcheck((local variable) string outAoutA.bool std.algorithm.searching.canFind!().canFind!(string, string)(string haystack, scope string needle) pure nothrow @nogc @safeConvenience function. Like find, but only returns whether or not the search
was successful.
For more information about pred see find.
Examples
const arr = [0, 1, 2, 3];
assert(canFind(arr, 2));
assert(!canFind(arr, 4));
// find one of several needles
assert(arr.canFind(3, 2));
assert(arr.canFind(3, 2) == 2); // second needle found
assert(arr.canFind([1, 3], 2) == 2);
assert(canFind(arr, [1, 2], [2, 3]));
assert(canFind(arr, [1, 2], [2, 3]) == 1);
assert(canFind(arr, [1, 7], [2, 3]));
assert(canFind(arr, [1, 7], [2, 3]) == 2);
assert(!canFind(arr, [1, 3], [2, 4]));
assert(canFind(arr, [1, 3], [2, 4]) == 0);
Example using a custom predicate.
Note that the needle appears as the second argument of the predicate.
auto words = [
"apple",
"beeswax",
"cardboard"
];
assert(!canFind(words, "bees"));
assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees"));
Search for multiple items in an array of items (search for needles in an array of haystacks)
string s1 = "aaa111aaa";
string s2 = "aaa222aaa";
string s3 = "aaa333aaa";
string s4 = "aaa444aaa";
const hay = [s1, s2, s3, s4];
assert(hay.canFind!(e => e.canFind("111", "222")));
canFind("recoverable returned 1"),
"__lsan_do_recoverable_leak_check should return 1 and not die",
(local variable) string outAoutA);
void sanitizers_lsan_gc_interplay.run.check(bool cond, string what, string output) @systemcheck((local variable) string outAoutA.bool std.algorithm.searching.canFind!().canFind!(string, string)(string haystack, scope string needle) pure nothrow @nogc @safeConvenience function. Like find, but only returns whether or not the search
was successful.
For more information about pred see find.
Examples
const arr = [0, 1, 2, 3];
assert(canFind(arr, 2));
assert(!canFind(arr, 4));
// find one of several needles
assert(arr.canFind(3, 2));
assert(arr.canFind(3, 2) == 2); // second needle found
assert(arr.canFind([1, 3], 2) == 2);
assert(canFind(arr, [1, 2], [2, 3]));
assert(canFind(arr, [1, 2], [2, 3]) == 1);
assert(canFind(arr, [1, 7], [2, 3]));
assert(canFind(arr, [1, 7], [2, 3]) == 2);
assert(!canFind(arr, [1, 3], [2, 4]));
assert(canFind(arr, [1, 3], [2, 4]) == 0);
Example using a custom predicate.
Note that the needle appears as the second argument of the predicate.
auto words = [
"apple",
"beeswax",
"cardboard"
];
assert(!canFind(words, "bees"));
assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees"));
Search for multiple items in an array of items (search for needles in an array of haystacks)
string s1 = "aaa111aaa";
string s2 = "aaa222aaa";
string s3 = "aaa333aaa";
string s4 = "aaa444aaa";
const hay = [s1, s2, s3, s4];
assert(hay.canFind!(e => e.canFind("111", "222")));
canFind("Direct leak of 1001 byte"),
"Q1: the unreachable malloc must be reported", (local variable) string outAoutA);
void sanitizers_lsan_gc_interplay.run.check(bool cond, string what, string output) @systemcheck((local variable) string outAoutA.bool std.algorithm.searching.canFind!().canFind!(string, string)(string haystack, scope string needle) pure nothrow @nogc @safeConvenience function. Like find, but only returns whether or not the search
was successful.
For more information about pred see find.
Examples
const arr = [0, 1, 2, 3];
assert(canFind(arr, 2));
assert(!canFind(arr, 4));
// find one of several needles
assert(arr.canFind(3, 2));
assert(arr.canFind(3, 2) == 2); // second needle found
assert(arr.canFind([1, 3], 2) == 2);
assert(canFind(arr, [1, 2], [2, 3]));
assert(canFind(arr, [1, 2], [2, 3]) == 1);
assert(canFind(arr, [1, 7], [2, 3]));
assert(canFind(arr, [1, 7], [2, 3]) == 2);
assert(!canFind(arr, [1, 3], [2, 4]));
assert(canFind(arr, [1, 3], [2, 4]) == 0);
Example using a custom predicate.
Note that the needle appears as the second argument of the predicate.
auto words = [
"apple",
"beeswax",
"cardboard"
];
assert(!canFind(words, "bees"));
assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees"));
Search for multiple items in an array of items (search for needles in an array of haystacks)
string s1 = "aaa111aaa";
string s2 = "aaa222aaa";
string s3 = "aaa333aaa";
string s4 = "aaa444aaa";
const hay = [s1, s2, s3, s4];
assert(hay.canFind!(e => e.canFind("111", "222")));
canFind("Direct leak of 2002 byte"),
"Q2: the GC-referenced malloc is a (known) FALSE POSITIVE — "
~ "LSan cannot see D GC pools", (local variable) string outAoutA);
void sanitizers_lsan_gc_interplay.run.check(bool cond, string what, string output) @systemcheck(!(local variable) string outAoutA.bool std.algorithm.searching.canFind!().canFind!(string, string)(string haystack, scope string needle) pure nothrow @nogc @safeConvenience function. Like find, but only returns whether or not the search
was successful.
For more information about pred see find.
Examples
const arr = [0, 1, 2, 3];
assert(canFind(arr, 2));
assert(!canFind(arr, 4));
// find one of several needles
assert(arr.canFind(3, 2));
assert(arr.canFind(3, 2) == 2); // second needle found
assert(arr.canFind([1, 3], 2) == 2);
assert(canFind(arr, [1, 2], [2, 3]));
assert(canFind(arr, [1, 2], [2, 3]) == 1);
assert(canFind(arr, [1, 7], [2, 3]));
assert(canFind(arr, [1, 7], [2, 3]) == 2);
assert(!canFind(arr, [1, 3], [2, 4]));
assert(canFind(arr, [1, 3], [2, 4]) == 0);
Example using a custom predicate.
Note that the needle appears as the second argument of the predicate.
auto words = [
"apple",
"beeswax",
"cardboard"
];
assert(!canFind(words, "bees"));
assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees"));
Search for multiple items in an array of items (search for needles in an array of haystacks)
string s1 = "aaa111aaa";
string s2 = "aaa222aaa";
string s3 = "aaa333aaa";
string s4 = "aaa444aaa";
const hay = [s1, s2, s3, s4];
assert(hay.canFind!(e => e.canFind("111", "222")));
canFind("4004 byte"),
"Q3: dropped GC allocations are invisible to LSan", (local variable) string outAoutA);
void sanitizers_lsan_gc_interplay.run.check(bool cond, string what, string output) @systemcheck(!(local variable) string outAoutA.bool std.algorithm.searching.canFind!().canFind!(string, string)(string haystack, scope string needle) pure nothrow @nogc @safeConvenience function. Like find, but only returns whether or not the search
was successful.
For more information about pred see find.
Examples
const arr = [0, 1, 2, 3];
assert(canFind(arr, 2));
assert(!canFind(arr, 4));
// find one of several needles
assert(arr.canFind(3, 2));
assert(arr.canFind(3, 2) == 2); // second needle found
assert(arr.canFind([1, 3], 2) == 2);
assert(canFind(arr, [1, 2], [2, 3]));
assert(canFind(arr, [1, 2], [2, 3]) == 1);
assert(canFind(arr, [1, 7], [2, 3]));
assert(canFind(arr, [1, 7], [2, 3]) == 2);
assert(!canFind(arr, [1, 3], [2, 4]));
assert(canFind(arr, [1, 3], [2, 4]) == 0);
Example using a custom predicate.
Note that the needle appears as the second argument of the predicate.
auto words = [
"apple",
"beeswax",
"cardboard"
];
assert(!canFind(words, "bees"));
assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees"));
Search for multiple items in an array of items (search for needles in an array of haystacks)
string s1 = "aaa111aaa";
string s2 = "aaa222aaa";
string s3 = "aaa333aaa";
string s4 = "aaa444aaa";
const hay = [s1, s2, s3, s4];
assert(hay.canFind!(e => e.canFind("111", "222")));
canFind("5005 byte"),
"Q4: a malloc reachable from __gshared data must NOT be reported",
(local variable) string outAoutA);
void sanitizers_lsan_gc_interplay.run.check(bool cond, string what, string output) @systemcheck(!(local variable) string outAoutA.bool std.algorithm.searching.canFind!().canFind!(string, string)(string haystack, scope string needle) pure nothrow @nogc @safeConvenience function. Like find, but only returns whether or not the search
was successful.
For more information about pred see find.
Examples
const arr = [0, 1, 2, 3];
assert(canFind(arr, 2));
assert(!canFind(arr, 4));
// find one of several needles
assert(arr.canFind(3, 2));
assert(arr.canFind(3, 2) == 2); // second needle found
assert(arr.canFind([1, 3], 2) == 2);
assert(canFind(arr, [1, 2], [2, 3]));
assert(canFind(arr, [1, 2], [2, 3]) == 1);
assert(canFind(arr, [1, 7], [2, 3]));
assert(canFind(arr, [1, 7], [2, 3]) == 2);
assert(!canFind(arr, [1, 3], [2, 4]));
assert(canFind(arr, [1, 3], [2, 4]) == 0);
Example using a custom predicate.
Note that the needle appears as the second argument of the predicate.
auto words = [
"apple",
"beeswax",
"cardboard"
];
assert(!canFind(words, "bees"));
assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees"));
Search for multiple items in an array of items (search for needles in an array of haystacks)
string s1 = "aaa111aaa";
string s2 = "aaa222aaa";
string s3 = "aaa333aaa";
string s4 = "aaa444aaa";
const hay = [s1, s2, s3, s4];
assert(hay.canFind!(e => e.canFind("111", "222")));
canFind("survived both manual checks"),
"__lsan_do_leak_check must be fatal when leaks were found", (local variable) string outAoutA);
// Child B: detect_leaks=0 — the manual entry points become no-ops.
(alias) object.string = stringstring (local variable) string outBoutB;
const (local variable) const(int) codeBcodeB = int sanitizers_lsan_gc_interplay.spawnChild(string[string] extraEnv, out string output)spawnChild(
[(constant) string sanitizers_lsan_gc_interplay.childEnvVar = "SANITIZERS_PROBE_CHILD"childEnvVar: "leaks", "LSAN_OPTIONS": "detect_leaks=0"], (local variable) string outBoutB);
void sanitizers_lsan_gc_interplay.run.check(bool cond, string what, string output) @systemcheck((local variable) const(int) codeBcodeB == 0, "child B should run to completion (exit 0)", (local variable) string outBoutB);
void sanitizers_lsan_gc_interplay.run.check(bool cond, string what, string output) @systemcheck((local variable) string outBoutB.bool std.algorithm.searching.canFind!().canFind!(string, string)(string haystack, scope string needle) pure nothrow @nogc @safeConvenience function. Like find, but only returns whether or not the search
was successful.
For more information about pred see find.
Examples
const arr = [0, 1, 2, 3];
assert(canFind(arr, 2));
assert(!canFind(arr, 4));
// find one of several needles
assert(arr.canFind(3, 2));
assert(arr.canFind(3, 2) == 2); // second needle found
assert(arr.canFind([1, 3], 2) == 2);
assert(canFind(arr, [1, 2], [2, 3]));
assert(canFind(arr, [1, 2], [2, 3]) == 1);
assert(canFind(arr, [1, 7], [2, 3]));
assert(canFind(arr, [1, 7], [2, 3]) == 2);
assert(!canFind(arr, [1, 3], [2, 4]));
assert(canFind(arr, [1, 3], [2, 4]) == 0);
Example using a custom predicate.
Note that the needle appears as the second argument of the predicate.
auto words = [
"apple",
"beeswax",
"cardboard"
];
assert(!canFind(words, "bees"));
assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees"));
Search for multiple items in an array of items (search for needles in an array of haystacks)
string s1 = "aaa111aaa";
string s2 = "aaa222aaa";
string s3 = "aaa333aaa";
string s4 = "aaa444aaa";
const hay = [s1, s2, s3, s4];
assert(hay.canFind!(e => e.canFind("111", "222")));
canFind("recoverable returned 0")
&& (local variable) string outBoutB.bool std.algorithm.searching.canFind!().canFind!(string, string)(string haystack, scope string needle) pure nothrow @nogc @safeConvenience function. Like find, but only returns whether or not the search
was successful.
For more information about pred see find.
Examples
const arr = [0, 1, 2, 3];
assert(canFind(arr, 2));
assert(!canFind(arr, 4));
// find one of several needles
assert(arr.canFind(3, 2));
assert(arr.canFind(3, 2) == 2); // second needle found
assert(arr.canFind([1, 3], 2) == 2);
assert(canFind(arr, [1, 2], [2, 3]));
assert(canFind(arr, [1, 2], [2, 3]) == 1);
assert(canFind(arr, [1, 7], [2, 3]));
assert(canFind(arr, [1, 7], [2, 3]) == 2);
assert(!canFind(arr, [1, 3], [2, 4]));
assert(canFind(arr, [1, 3], [2, 4]) == 0);
Example using a custom predicate.
Note that the needle appears as the second argument of the predicate.
auto words = [
"apple",
"beeswax",
"cardboard"
];
assert(!canFind(words, "bees"));
assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees"));
Search for multiple items in an array of items (search for needles in an array of haystacks)
string s1 = "aaa111aaa";
string s2 = "aaa222aaa";
string s3 = "aaa333aaa";
string s4 = "aaa444aaa";
const hay = [s1, s2, s3, s4];
assert(hay.canFind!(e => e.canFind("111", "222")));
canFind("survived both manual checks"),
"detect_leaks=0 must disable the manual checks too", (local variable) string outBoutB);
void sanitizers_lsan_gc_interplay.run.check(bool cond, string what, string output) @systemcheck(!(local variable) string outBoutB.bool std.algorithm.searching.canFind!().canFind!(string, string)(string haystack, scope string needle) pure nothrow @nogc @safeConvenience function. Like find, but only returns whether or not the search
was successful.
For more information about pred see find.
Examples
const arr = [0, 1, 2, 3];
assert(canFind(arr, 2));
assert(!canFind(arr, 4));
// find one of several needles
assert(arr.canFind(3, 2));
assert(arr.canFind(3, 2) == 2); // second needle found
assert(arr.canFind([1, 3], 2) == 2);
assert(canFind(arr, [1, 2], [2, 3]));
assert(canFind(arr, [1, 2], [2, 3]) == 1);
assert(canFind(arr, [1, 7], [2, 3]));
assert(canFind(arr, [1, 7], [2, 3]) == 2);
assert(!canFind(arr, [1, 3], [2, 4]));
assert(canFind(arr, [1, 3], [2, 4]) == 0);
Example using a custom predicate.
Note that the needle appears as the second argument of the predicate.
auto words = [
"apple",
"beeswax",
"cardboard"
];
assert(!canFind(words, "bees"));
assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees"));
Search for multiple items in an array of items (search for needles in an array of haystacks)
string s1 = "aaa111aaa";
string s2 = "aaa222aaa";
string s3 = "aaa333aaa";
string s4 = "aaa444aaa";
const hay = [s1, s2, s3, s4];
assert(hay.canFind!(e => e.canFind("111", "222")));
canFind("LeakSanitizer"),
"no report of any kind under detect_leaks=0", (local variable) string outBoutB);
void std.stdio.writefln!char(in char[] fmt) @safeEquivalent to writef(fmt, args, '\n').
writefln("PASS: LSan vs the D GC — true malloc leak reported, "
~ "GC-referenced malloc falsely reported (blind spot), GC leak "
~ "invisible, global-rooted malloc silent; exit 23; "
~ "detect_leaks=0 disables manual checks");
return 0;
}
}
int int D main()main()
{
version (linuxlinux)
return int sanitizers_lsan_gc_interplay.run()run();
else
{
import std.stdio : writefln;
writefln("SKIP: this LSan probe is Linux-only");
return 0;
}
}