Skip to content

Commit 4055f1d

Browse files
committed
Manually merge PR188 to work around a low-level bug with yaml used through the C-API, which we rely on in the PAM module in our sshd+sftpsubsys service.
git-svn-id: svn+ssh://svn.code.sf.net/p/migrid/code/trunk@6204 b75ad72c-e7d7-11dd-a971-7dbc132099af
1 parent 486a392 commit 4055f1d

File tree

1 file changed

+27
-5
lines changed

1 file changed

+27
-5
lines changed

mig/shared/serial.py

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
# --- BEGIN_HEADER ---
55
#
66
# serial - object serialization operations using pickle, json or yaml
7-
# Copyright (C) 2003-2024 The MiG Project lead by Brian Vinter
7+
# Copyright (C) 2003-2025 The MiG Project by the Science HPC Center at UCPH
88
#
99
# This file is part of MiG.
1010
#
@@ -37,14 +37,32 @@
3737
print("ERROR: failed to init compatibility setup")
3838
exit(1)
3939

40-
import json
41-
import yaml
42-
43-
# Python 2 requires explicit cPickle where as python 3 defaults to it
40+
# Python 2 requires explicit cPickle whereas python 3 defaults to it
4441
try:
4542
import cPickle as pickle
4643
except ImportError:
4744
import pickle
45+
# IMPORTANT: lazy-load json and yaml mainly in order to work around PAM crashes
46+
# seen in sshd+sftpsubsys sessions. Apparently there's a bug / C-API
47+
# incompatibility when using yaml in embedded python interpreters,
48+
# due to yaml using its own nested C-extensions. In practice it
49+
# results in a metaclass conflict TypeError upon yaml re-init there
50+
# like described in
51+
# https://github.com/ros-drivers/rosserial/issues/450
52+
try:
53+
import json
54+
except ImportError:
55+
json = None
56+
try:
57+
import yaml
58+
except ImportError:
59+
yaml = None
60+
except TypeError:
61+
# NOTE: this should not really happen but it does with sshd+sftpsubsys in
62+
# our PAM module hooking into this code as described above. We don't
63+
# actually need yaml in that case so just silently ignore it here and
64+
# only raise an assertion error if used below.
65+
yaml = None
4866

4967
from mig.shared.base import force_native_str_rec, force_utf8_rec
5068

@@ -65,10 +83,12 @@ def dumps(data, protocol=0, serializer='pickle', **kwargs):
6583
# pickle dumps already returns bytes - skip post conversion
6684
postprocess_helper = None
6785
if serializer == 'json':
86+
assert json is not None, "JSON module must be loaded for actual use"
6887
serial_helper = json.dumps
6988
# json dumps expects and returns native string - skip pre conversion
7089
preprocess_helper = None
7190
if serializer == 'yaml':
91+
assert yaml is not None, "YAML module must be loaded for actual use"
7292
serial_helper = yaml.dump
7393
if not serial_helper:
7494
raise ValueError("invalid serializer %r provided" % serializer)
@@ -104,8 +124,10 @@ def loads(data, serializer='pickle', **kwargs):
104124
if serializer == 'pickle':
105125
serial_helper = pickle.loads
106126
if serializer == 'json':
127+
assert json is not None, "JSON module must be loaded for actual use"
107128
serial_helper = json.loads
108129
if serializer == 'yaml':
130+
assert yaml is not None, "YAML module must be loaded for actual use"
109131
# NOTE: yaml load supports both string and file-like obj
110132
serial_helper = yaml.load
111133
kwargs['Loader'] = yaml.SafeLoader

0 commit comments

Comments
 (0)