diff --git a/src/pugixml.cpp b/src/pugixml.cpp
index 11873831363892630e57d27ab1febd9cc38fffc5..109a635f379e766ef3fdaaad7a75082889d5a2bc 100644
--- a/src/pugixml.cpp
+++ b/src/pugixml.cpp
@@ -164,6 +164,8 @@ PUGI__NS_BEGIN
 		static deallocation_function deallocate;
 	};
 
+	// Global allocation functions are stored in class statics so that in header mode linker deduplicates them
+	// Without a template<> we'll get multiple definitions of the same static
 	template <typename T> allocation_function xml_memory_management_function_storage<T>::allocate = default_allocate;
 	template <typename T> deallocation_function xml_memory_management_function_storage<T>::deallocate = default_deallocate;
 
@@ -3735,8 +3737,11 @@ PUGI__NS_BEGIN
 		{
 			xml_attribute_struct* da = append_new_attribute(dn, get_allocator(dn));
 
-			node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc);
-			node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc);
+			if (da)
+			{
+				node_copy_string(da->name, da->header, xml_memory_page_name_allocated_mask, sa->name, sa->header, shared_alloc);
+				node_copy_string(da->value, da->header, xml_memory_page_value_allocated_mask, sa->value, sa->header, shared_alloc);
+			}
 		}
 	}
 
diff --git a/tests/test_dom_modify.cpp b/tests/test_dom_modify.cpp
index 01b562a76e8446988d594601bd514a6351c49aaa..07fe6dc4966e0502e7db6598aad2acd2fb9195b0 100644
--- a/tests/test_dom_modify.cpp
+++ b/tests/test_dom_modify.cpp
@@ -1361,13 +1361,22 @@ TEST_XML(dom_node_copyless_taint, "<node attr=\"value\" />")
 	CHECK_NODE(doc, STR("<nod1 attr=\"value\" /><node attr=\"valu2\" /><node att3=\"value\" />"));
 }
 
-TEST_XML(dom_node_copy_out_of_memory, "<node><child1 attr1='value1' attr2='value2' /><child2 /><child3>text1<child4 />text2</child3></node>")
+TEST_XML(dom_node_copy_out_of_memory_node, "<node><child1 /><child2 /><child3>text1<child4 />text2</child3></node>")
 {
 	test_runner::_memory_fail_threshold = 32768 * 2 + 4096;
 
-    xml_document copy;
-    for (int i = 0; i < 100; ++i)
-        copy.append_copy(doc.first_child());
+	xml_document copy;
+	for (int i = 0; i < 1000; ++i)
+		copy.append_copy(doc.first_child());
+}
+
+TEST_XML(dom_node_copy_out_of_memory_attr, "<node attr1='' attr2='' attr3='' attr4='' attr5='' attr6='' attr7='' attr8='' attr9='' attr10='' attr11='' attr12='' attr13='' attr14='' attr15='' />")
+{
+	test_runner::_memory_fail_threshold = 32768 * 2 + 4096;
+
+	xml_document copy;
+	for (int i = 0; i < 1000; ++i)
+		copy.append_copy(doc.first_child());
 }
 
 TEST_XML(dom_node_remove_deallocate, "<node attr='value'>text</node>")