/*
*
- * Copyright (C) 1994-2024, OFFIS e.V.
+ * Copyright (C) 1994-2026, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were partly developed by
unsigned long length;
*rtnLength = 0;
+ /* The transient list built here ends up as userInfo->extNegList of the
+ * outgoing PDU; via the shallow appendList() it borrows the sub-item
+ * pointers from the params-owned list. destroyUserInformationLists()
+ * (called once the PDU has been streamed) releases only the container,
+ * leaving the items in place for DUL_ClearServiceParameters() to free
+ * through the params side. See the ownership note in
+ * destroyUserInformationLists() (helpers.cc).
+ */
if (type == DUL_TYPEASSOCIATERQ && params->requestedExtNegList != NULL) {
*lst = new SOPClassExtendedNegotiationSubItemList;
if (*lst == NULL) return EC_MemoryExhausted;
/*
*
- * Copyright (C) 1994-2025, OFFIS e.V.
+ * Copyright (C) 1994-2026, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were partly developed by
}
- /* extended negotiation */
+ /* Extended negotiation: ownership of the sub-item objects transfers
+ * from the transient assoc.userInfo.extNegList to service->acceptedExtNegList
+ * via the shallow appendList(). The destroyUserInformationLists() call
+ * a few lines below deliberately frees only the list container; the
+ * items themselves will be released by DUL_ClearServiceParameters()
+ * through the service parameter list. See the ownership note in
+ * destroyUserInformationLists() (helpers.cc).
+ */
if (assoc.userInfo.extNegList != NULL) {
service->acceptedExtNegList = new SOPClassExtendedNegotiationSubItemList;
if (service->acceptedExtNegList == NULL) return EC_MemoryExhausted;
return DUL_PCTRANSLATIONFAILURE;
}
- /* extended negotiation */
+ /* Extended negotiation: ownership of the sub-item objects transfers
+ * from the transient assoc.userInfo.extNegList to service->requestedExtNegList
+ * via the shallow appendList(). The destroyUserInformationLists() call
+ * a few lines below frees only the list container; the items themselves
+ * are released later by DUL_ClearServiceParameters() through the service
+ * parameter list. See the ownership note in destroyUserInformationLists()
+ * (helpers.cc).
+ */
if (assoc.userInfo.extNegList != NULL) {
service->requestedExtNegList = new SOPClassExtendedNegotiationSubItemList;
if (service->requestedExtNegList == NULL) return EC_MemoryExhausted;
/*
*
- * Copyright (C) 1994-2024, OFFIS e.V.
+ * Copyright (C) 1994-2026, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were partly developed by
if (cond.bad())
{
destroyAssociatePDUPresentationContextList(&assoc->presentationContextList);
+ /* On a parse error the parsed extended negotiation sub-items are only
+ * held by assoc->userInfo.extNegList; no service parameter list has
+ * adopted them yet. destroyUserInformationLists() releases the list
+ * container but not its members (see the ownership note there), so
+ * the SOPClassExtendedNegotiationSubItem objects must be released
+ * explicitly here.
+ */
+ if (assoc->userInfo.extNegList != NULL)
+ deleteListMembers(*assoc->userInfo.extNegList);
destroyUserInformationLists(&assoc->userInfo);
}
return cond;
extNeg = new SOPClassExtendedNegotiationSubItem;
if (extNeg == NULL) return EC_MemoryExhausted;
cond = parseExtNeg(extNeg, buf, &length, userLength);
- if (cond.bad()) return cond;
+ if (cond.bad())
+ {
+ /* extNeg has not yet been pushed to extNegList, so the
+ * outer cleanup in parseAssociate would not see it. Release
+ * it here. parseExtNeg only returns errors before allocating
+ * extNeg->serviceClassAppInfo, so there is no inner buffer
+ * to free.
+ */
+ delete extNeg;
+ return cond;
+ }
if (userInfo->extNegList == NULL)
{
userInfo->extNegList = new SOPClassExtendedNegotiationSubItemList;
#include "dcmtk/dcmnet/extneg.h"
+/* Shallow copy: 'to' receives the same SOPClassExtendedNegotiationSubItem*
+ * pointers held by 'from'. Both lists end up sharing the items; exactly one
+ * side may eventually call deleteListMembers() on them. See the ownership
+ * note in destroyUserInformationLists() (helpers.cc) for which side that is
+ * on each call path.
+ */
void appendList(const SOPClassExtendedNegotiationSubItemList& from, SOPClassExtendedNegotiationSubItemList& to)
{
OFListConstIterator(SOPClassExtendedNegotiationSubItem*) i = from.begin();
/*
*
- * Copyright (C) 2021, OFFIS e.V.
+ * Copyright (C) 2021-2026, OFFIS e.V.
* All rights reserved. See COPYRIGHT file for details.
*
* This software and supporting documentation were partly developed by
}
LST_Destroy(&userInfo->SCUSCPRoleList);
- /* extended negotiation */
+ /* Extended negotiation: the list contents (SOPClassExtendedNegotiationSubItem*)
+ * are intentionally NOT deleted here. On all normal paths the items are
+ * shared (via the shallow appendList()) with the owning service parameter
+ * list (params->{requested,accepted}ExtNegList in DUL_ASSOCIATESERVICEPARAMETERS),
+ * which releases them through DUL_ClearServiceParameters() ->
+ * deleteListMembers(). Callers with no service-side owner (e.g. the
+ * parse-error cleanup in parseAssociate()) must call deleteListMembers()
+ * themselves before invoking this function.
+ */
delete userInfo->extNegList;
userInfo->extNegList = NULL;