Segfault on enumeration of GjSFileImporter properties when a searchpath entry contains a symlink
Reproduction steps
touch target
mkdir withsymlink
cd withsymlink
ln -s ../target symlink
cd ..
echo "
imports.searchPath.push('$PWD/withsymlink');
print(Object.keys(imports));
" > segfault.js
gjs segfault.js
Further test cases: symlink-bug.tgz (file creation order matter when theres multiple files)
Cause
I've done some debugging and located the cause: The segfault happens here - g_file_get_basename(file)
returns NULL
.
file
is not NULL
...
The behavior is explained by how the enumerator is created: We only ask for G_FILE_ATTRIBUTE_STANDARD_TYPE information - ie. only the filename. At the same time we request that links should be followed (G_FILE_QUERY_INFO_NONE)
When links are followed it seem like the name of the target is considered the filename, but that information is not available so glib returns NULL
...
Digging a bit deeper: the segfault only happens if the symlink is the oldest file in the directory. If a older regular file exist g_file_get_basename
simply return the name of the previous file when we arrive at the symlink!
I guess strictly speaking only the last part i a real bug in GLib, but the rest it's certainly a huge gotcha :)
Fix
Asking for the symlink target in addition to the name fixes the problem:
GjsAutoUnref<GFileEnumerator> direnum =
g_file_enumerate_children(dir, "standard::symlink-target,standard::name",
G_FILE_QUERY_INFO_NONE, NULL, NULL);
but then the module name become the target name, not the symlink name which seems strange.
Requesting G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS
seems better: dont-follow-symlink.patch (then the symlink name is considered the filename) Loading the symlinked module also work.
Shameless plug: I stumbled across this while working on PaperWM and gnome-shell-mode: a emacs mode for gnome-shell extensions with good autocompletion, send-code-to-gnome-shell, module/extension reload (with some caveats) and rudimentary documentation lookup.