Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -697,7 +697,7 @@ PythonObject PythonDictionary::GetItemForKey(const PythonObject &key) const {

Expected<PythonObject>
PythonDictionary::GetItem(const PythonObject &key) const {
if (!IsValid())
if (!IsValid() || !key.IsValid())
return nullDeref();
PyObject *o = PyDict_GetItemWithError(m_py_obj, key.get());
if (PyErr_Occurred())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,30 @@ TEST_F(PythonDataObjectsTest, TestPythonDictionaryValueEquality) {
EXPECT_EQ(value_1, chk_str.GetString());
}

TEST_F(PythonDataObjectsTest, TestPythonDictionaryGetItemWithInvalidKey) {
// A PythonString constructed from invalid UTF-8 silently fails (the
// PyUnicode_FromStringAndSize call returns NULL) and leaves m_py_obj == NULL.
// PythonDictionary::GetItem(const PythonObject&) must not pass that NULL key
// through to PyDict_GetItemWithError, which would then dereference it and
// crash.
llvm::StringRef invalid_utf8("\xd0p", 2);
PythonString invalid_key(invalid_utf8);
EXPECT_FALSE(invalid_key.IsValid());

PythonDictionary dict(PyInitialValue::Empty);
dict.SetItemForKey(PythonString("real_key"), PythonInteger(42));

// GetItem must return an error (not crash) when given an invalid key.
llvm::Expected<PythonObject> item = dict.GetItem(invalid_key);
EXPECT_FALSE(static_cast<bool>(item));
llvm::consumeError(item.takeError());

// GetItemForKey wraps GetItem, consumes any error, and returns an empty
// PythonObject. It must not crash either.
PythonObject result = dict.GetItemForKey(invalid_key);
EXPECT_FALSE(result.IsAllocated());
}

TEST_F(PythonDataObjectsTest, TestPythonDictionaryManipulation) {
// Test that manipulation of a dictionary behaves correctly when wrapped
// by a PythonDictionary.
Expand Down