Prechádzať zdrojové kódy

replace alloca with variable-length arrays and alloca as fallback

Julius Pfrommer 7 rokov pred
rodič
commit
46979d3b87

+ 4 - 7
examples/encryption/server_basic128rsa15.c

@@ -56,15 +56,12 @@ int main(int argc, char* argv[]) {
     UA_ByteString privateKey = loadFile(argv[2]);
 
     /* Load the trustlist */
-    UA_ByteString *trustList = NULL;
     size_t trustListSize = 0;
-    if(argc > 3) {
+    if(argc > 3)
         trustListSize = (size_t)argc-3;
-        trustList = (UA_ByteString*)
-            UA_alloca(sizeof(UA_ByteString) * trustListSize);
-        for(size_t i = 0; i < trustListSize; i++)
-            trustList[i] = loadFile(argv[i+3]);
-    }
+    UA_STACKARRAY(UA_ByteString, trustList, trustListSize);
+    for(size_t i = 0; i < trustListSize; i++)
+        trustList[i] = loadFile(argv[i+3]);
 
     /* Loading of a revocation list currentlu unsupported */
     UA_ByteString *revocationList = NULL;

+ 5 - 8
examples/server.c

@@ -142,15 +142,12 @@ main(int argc, char **argv) {
     UA_ByteString privateKey = loadFile(argv[2]);
 
     /* Load the trustlist */
-    UA_ByteString *trustList = NULL;
     size_t trustListSize = 0;
-    if(argc > 3) {
-        trustListSize = (size_t)argc - 3;
-        trustList = (UA_ByteString *)
-            UA_alloca(sizeof(UA_ByteString) * trustListSize);
-        for(size_t i = 0; i < trustListSize; i++)
-            trustList[i] = loadFile(argv[i + 3]);
-    }
+    if(argc > 3)
+        trustListSize = (size_t)argc-3;
+    UA_STACKARRAY(UA_ByteString, trustList, trustListSize);
+    for(size_t i = 0; i < trustListSize; i++)
+        trustList[i] = loadFile(argv[i+3]);
 
     /* Loading of a revocation list currently unsupported */
     UA_ByteString *revocationList = NULL;

+ 8 - 3
include/ua_config.h.in

@@ -130,13 +130,18 @@ extern "C" {
 
 #endif
 
+/* Stack-allocation of memory. Use C99 variable-length arrays if possible.
+ * Otherwise revert to alloca. Note that alloca is not supported on some
+ * plattforms. */
 #if defined(__GNUC__) || defined(__clang__)
-# define UA_alloca(size) __builtin_alloca (size)
+# define UA_STACKARRAY(TYPE, NAME, SIZE) TYPE NAME[SIZE]
 #elif defined(_WIN32)
-# define UA_alloca(SIZE) _alloca(SIZE)
+# define UA_STACKARRAY(TYPE, NAME, SIZE) \
+    TYPE *NAME = (TYPE*)_alloca(sizeof(TYPE) * SIZE)
 #else
 # include <alloca.h>
-# define UA_alloca(SIZE) alloca(SIZE)
+# define UA_STACKARRAY(TYPE, NAME, SIZE) \
+    TYPE *NAME = (TYPE*)alloca(sizeof(TYPE) * SIZE)
 #endif
 
 /**

+ 4 - 2
src/client/ua_client.c

@@ -159,7 +159,8 @@ processAsyncResponse(UA_Client *client, UA_UInt32 requestId, const UA_NodeId *re
         return UA_STATUSCODE_BADREQUESTHEADERINVALID;
 
     /* Allocate the response */
-    void *response = UA_alloca(ac->responseType->memSize);
+    UA_STACKARRAY(UA_Byte, responseBuf, ac->responseType->memSize);
+    void *response = (void*)(uintptr_t)&responseBuf[0]; /* workaround aliasing rules */
 
     /* Verify the type of the response */
     const UA_DataType *responseType = ac->responseType;
@@ -372,7 +373,8 @@ void
 UA_Client_AsyncService_cancel(UA_Client *client, AsyncServiceCall *ac,
                               UA_StatusCode statusCode) {
     /* Create an empty response with the statuscode */
-    void *resp = UA_alloca(ac->responseType->memSize);
+    UA_STACKARRAY(UA_Byte, responseBuf, ac->responseType->memSize);
+    void *resp = (void*)(uintptr_t)&responseBuf[0]; /* workaround aliasing rules */
     UA_init(resp, ac->responseType);
     ((UA_ResponseHeader*)resp)->serviceResult = statusCode;
 

+ 2 - 4
src/client/ua_client_subscriptions.c

@@ -113,8 +113,7 @@ UA_Client_Subscription_deleteInternal(UA_Client *client, UA_Client_Subscription
 
 UA_DeleteSubscriptionsResponse UA_EXPORT
 UA_Client_Subscriptions_delete(UA_Client *client, const UA_DeleteSubscriptionsRequest request) {
-    UA_Client_Subscription **subs = (UA_Client_Subscription**)
-        UA_alloca(sizeof(void*) * request.subscriptionIdsSize);
+    UA_STACKARRAY(UA_Client_Subscription*, subs, request.subscriptionIdsSize);
     memset(subs, 0, sizeof(void*) * request.subscriptionIdsSize);
 
     /* temporary remove the subscriptions from the list */
@@ -227,8 +226,7 @@ __UA_Client_MonitoredItems_create(UA_Client *client,
     UA_Client_Subscription *sub = NULL;
     
     /* Allocate the memory for internal representations */
-    UA_Client_MonitoredItem **mis = (UA_Client_MonitoredItem**)
-        UA_alloca(sizeof(void*) * itemsToCreateSize);
+    UA_STACKARRAY(UA_Client_MonitoredItem*, mis, itemsToCreateSize);
     memset(mis, 0, sizeof(void*) * itemsToCreateSize);
     for(size_t i = 0; i < itemsToCreateSize; i++) {
         mis[i] = (UA_Client_MonitoredItem*)UA_malloc(sizeof(UA_Client_MonitoredItem));

+ 6 - 12
src/client/ua_client_subscriptions_deprecated.c

@@ -162,12 +162,9 @@ addMonitoredItems(UA_Client *client, const UA_UInt32 subscriptionId,
                   UA_MonitoredItemHandlingFunction *hfs, void **hfContexts,
                   UA_StatusCode *itemResults, UA_UInt32 *newMonitoredItemIds) {
     /* Create array of wrappers and callbacks */
-    dataChangeCallbackWrapper **wrappers = (dataChangeCallbackWrapper**)
-        UA_alloca(sizeof(dataChangeCallbackWrapper*) * itemsSize);
-    UA_Client_DeleteMonitoredItemCallback *deleteCbs = (UA_Client_DeleteMonitoredItemCallback*)
-        UA_alloca(sizeof(UA_Client_DeleteMonitoredItemCallback) * itemsSize);
-    UA_Client_DataChangeNotificationCallback *wrapperCbs = (UA_Client_DataChangeNotificationCallback*)
-        UA_alloca(sizeof(UA_MonitoredItemHandlingFunction) * itemsSize);
+    UA_STACKARRAY(dataChangeCallbackWrapper*, wrappers, itemsSize);
+    UA_STACKARRAY(UA_Client_DeleteMonitoredItemCallback, deleteCbs, itemsSize);
+    UA_STACKARRAY(UA_Client_DataChangeNotificationCallback, wrapperCbs, itemsSize);
 
     for(size_t i = 0; i < itemsSize; i++) {
         wrappers[i] = (dataChangeCallbackWrapper*)UA_malloc(sizeof(dataChangeCallbackWrapper));
@@ -249,12 +246,9 @@ addMonitoredEvents(UA_Client *client, const UA_UInt32 subscriptionId,
                    void **hfContexts, UA_StatusCode *itemResults,
                    UA_UInt32 *newMonitoredItemIds) {
     /* Create array of wrappers and callbacks */
-    eventCallbackWrapper **wrappers = (eventCallbackWrapper**)
-        UA_alloca(sizeof(dataChangeCallbackWrapper*) * itemsSize);
-    UA_Client_DeleteMonitoredItemCallback *deleteCbs = (UA_Client_DeleteMonitoredItemCallback*)
-        UA_alloca(sizeof(UA_Client_DeleteMonitoredItemCallback) * itemsSize);
-    UA_Client_EventNotificationCallback *wrapperCbs = (UA_Client_EventNotificationCallback*)
-        UA_alloca(sizeof(UA_MonitoredItemHandlingFunction) * itemsSize);
+    UA_STACKARRAY(eventCallbackWrapper*, wrappers, itemsSize);
+    UA_STACKARRAY(UA_Client_DeleteMonitoredItemCallback, deleteCbs, itemsSize);
+    UA_STACKARRAY(UA_Client_EventNotificationCallback, wrapperCbs, itemsSize);
 
     for(size_t i = 0; i < itemsSize; i++) {
         wrappers[i] = (eventCallbackWrapper*)UA_malloc(sizeof(eventCallbackWrapper));

+ 4 - 4
src/server/ua_server_binary.c

@@ -26,7 +26,6 @@
 #include "ua_types_generated_handling.h"
 #include "ua_securitypolicy_none.h"
 
-
 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
 // store the authentication token and session ID so we can help fuzzing by setting
 // these values in the next request automatically
@@ -52,7 +51,7 @@ sendServiceFault(UA_SecureChannel *channel, const UA_ByteString *msg,
     UA_StatusCode retval = UA_RequestHeader_decodeBinary(msg, &offset, &requestHeader);
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
-    void *response = UA_alloca(responseType->memSize);
+    UA_STACKARRAY(UA_Byte, response, responseType->memSize);
     UA_init(response, responseType);
     UA_ResponseHeader *responseHeader = (UA_ResponseHeader*)response;
     responseHeader->requestHandle = requestHeader.requestHandle;
@@ -423,7 +422,7 @@ processMSG(UA_Server *server, UA_SecureChannel *channel,
     UA_assert(responseType);
 
     /* Decode the request */
-    void *request = UA_alloca(requestType->memSize);
+    UA_STACKARRAY(UA_Byte, request, requestType->memSize);
     UA_RequestHeader *requestHeader = (UA_RequestHeader*)request;
     retval = UA_decodeBinary(msg, &offset, request, requestType,
                              server->config.customDataTypesSize,
@@ -435,7 +434,8 @@ processMSG(UA_Server *server, UA_SecureChannel *channel,
     }
 
     /* Prepare the respone */
-    void *response = UA_alloca(responseType->memSize);
+    UA_STACKARRAY(UA_Byte, responseBuf, responseType->memSize);
+    void *response = (void*)(uintptr_t)&responseBuf[0]; /* Get around aliasing rules */
     UA_init(response, responseType);
     UA_Session *session = NULL; /* must be initialized before goto send_response */
 

+ 2 - 6
src/server/ua_server_discovery.c

@@ -70,12 +70,8 @@ register_server_with_discovery_server(UA_Server *server,
     size_t config_discurls = server->config.applicationDescription.discoveryUrlsSize;
     size_t nl_discurls = server->config.networkLayersSize;
     size_t total_discurls = config_discurls + nl_discurls;
-    request.server.discoveryUrls = (UA_String*)UA_alloca(sizeof(UA_String) * total_discurls);
-    if(!request.server.discoveryUrls) {
-        UA_Client_disconnect(client);
-        UA_Client_delete(client);
-        return UA_STATUSCODE_BADOUTOFMEMORY;
-    }
+    UA_STACKARRAY(UA_String, urlsBuf, total_discurls);
+    request.server.discoveryUrls = urlsBuf;
     request.server.discoveryUrlsSize = total_discurls;
 
     for(size_t i = 0; i < config_discurls; ++i)

+ 9 - 5
src/server/ua_server_ns0.c

@@ -108,14 +108,18 @@ addVariableTypeNode(UA_Server *server, char* name, UA_UInt32 variabletypeid,
     attr.dataType = UA_NODEID_NUMERIC(0, dataType);
     attr.isAbstract = isAbstract;
     attr.valueRank = valueRank;
+
     if(type) {
-        void *val = UA_alloca(type->memSize);
-        UA_init(val, type);
-        UA_Variant_setScalar(&attr.value, val, type);
+        UA_STACKARRAY(UA_Byte, tempVal, type->memSize);
+        UA_init(tempVal, type);
+        UA_Variant_setScalar(&attr.value, tempVal, type);
+        return UA_Server_addVariableTypeNode(server, UA_NODEID_NUMERIC(0, variabletypeid),
+                                             UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NULL,
+                                             UA_QUALIFIEDNAME(0, name), UA_NODEID_NULL, attr, NULL, NULL);
     }
     return UA_Server_addVariableTypeNode(server, UA_NODEID_NUMERIC(0, variabletypeid),
-                                  UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NULL,
-                                  UA_QUALIFIEDNAME(0, name), UA_NODEID_NULL, attr, NULL, NULL);
+                                         UA_NODEID_NUMERIC(0, parentid), UA_NODEID_NULL,
+                                         UA_QUALIFIEDNAME(0, name), UA_NODEID_NULL, attr, NULL, NULL);
 }
 
 /**********************/

+ 2 - 2
src/server/ua_services_discovery.c

@@ -265,8 +265,8 @@ void Service_GetEndpoints(UA_Server *server, UA_Session *session,
 
     /* test if the supported binary profile shall be returned */
     size_t reSize = sizeof(UA_Boolean) * server->config.endpointsSize;
-    UA_Boolean *relevant_endpoints = (UA_Boolean *)UA_alloca(reSize);
-    memset(relevant_endpoints, 0, sizeof(UA_Boolean) * server->config.endpointsSize);
+    UA_STACKARRAY(UA_Boolean, relevant_endpoints, reSize);
+    memset(relevant_endpoints, 0, reSize);
     size_t relevant_count = 0;
     if(request->profileUrisSize == 0) {
         for(size_t j = 0; j < server->config.endpointsSize; ++j)

+ 2 - 3
src/server/ua_services_discovery_multicast.c

@@ -194,8 +194,7 @@ void Service_FindServersOnNetwork(UA_Server *server, UA_Session *session,
 
     /* Iterate over all records and add to filtered list */
     UA_UInt32 filteredCount = 0;
-    UA_ServerOnNetwork** filtered =
-        (UA_ServerOnNetwork**)UA_alloca(sizeof(UA_ServerOnNetwork*) * recordCount);
+    UA_STACKARRAY(UA_ServerOnNetwork*, filtered, recordCount);
     serverOnNetwork_list_entry* current;
     LIST_FOREACH(current, &server->serverOnNetwork, pointers) {
         if(filteredCount >= recordCount)
@@ -553,8 +552,8 @@ UA_Discovery_addRecord(UA_Server *server, const UA_String *servername,
     mdns_set_address_record(server, fullServiceDomain, localDomain);
 
     // TXT record: [servername]-[hostname]._opcua-tcp._tcp.local. TXT path=/ caps=NA,DA,...
+    UA_STACKARRAY(char, pathChars, path->length + 1);
     if(createTxt) {
-        char *pathChars = (char *)UA_alloca(path->length + 1);
         memcpy(pathChars, path->data, path->length);
         pathChars[path->length] = 0;
         mdns_create_txt(server, fullServiceDomain, pathChars, capabilites,

+ 11 - 6
src/server/ua_services_session.c

@@ -36,18 +36,23 @@ signCreateSessionResponse(UA_Server *server, UA_SecureChannel *channel,
     if(retval != UA_STATUSCODE_GOOD)
         return retval;
 
-    /* Sign the signature */
+    /* Allocate a temp buffer */
     size_t dataToSignSize = request->clientCertificate.length + request->clientNonce.length;
-    /* Prevent stack-smashing. TODO: Compute MaxSenderCertificateSize */
-    if(dataToSignSize > 4096)
-        return UA_STATUSCODE_BADINTERNALERROR;
+    UA_ByteString dataToSign;
+    retval = UA_ByteString_allocBuffer(&dataToSign, dataToSignSize);
+    if(retval != UA_STATUSCODE_GOOD)
+        return retval; /* signatureData->signature is cleaned up with the response */
 
-    UA_ByteString dataToSign = {dataToSignSize, (UA_Byte*)UA_alloca(dataToSignSize)};
+    /* Sign the signature */
     memcpy(dataToSign.data, request->clientCertificate.data, request->clientCertificate.length);
     memcpy(dataToSign.data + request->clientCertificate.length,
            request->clientNonce.data, request->clientNonce.length);
-    return securityPolicy->certificateSigningAlgorithm.
+    retval = securityPolicy->certificateSigningAlgorithm.
         sign(securityPolicy, channel->channelContext, &dataToSign, &signatureData->signature);
+
+    /* Clean up */
+    UA_ByteString_deleteMembers(&dataToSign);
+    return retval;
 }
 
 void

+ 1 - 1
src/server/ua_services_view.c

@@ -250,7 +250,7 @@ void
 Operation_Browse(UA_Server *server, UA_Session *session, UA_UInt32 *maxrefs,
                  const UA_BrowseDescription *descr, UA_BrowseResult *result) {
     /* Stack-allocate a temporary cp */
-    ContinuationPointEntry *cp = (ContinuationPointEntry*)UA_alloca(sizeof(ContinuationPointEntry));
+    UA_STACKARRAY(ContinuationPointEntry, cp, 1);
     memset(cp, 0, sizeof(ContinuationPointEntry));
     cp->maxReferences = *maxrefs;
     cp->browseDescription = *descr; /* Shallow copy. Deep-copy later if we persist the cp. */

+ 2 - 2
src/server/ua_subscription.c

@@ -339,9 +339,9 @@ UA_Subscription_publish(UA_Server *server, UA_Subscription *sub) {
 
     /* Get the available sequence numbers from the retransmission queue */
     size_t available = sub->retransmissionQueueSize;
+    UA_STACKARRAY(UA_UInt32, seqNumbers, available);
     if(available > 0) {
-        response->availableSequenceNumbers =
-            (UA_UInt32*)UA_alloca(available * sizeof(UA_UInt32));
+        response->availableSequenceNumbers = seqNumbers;
         response->availableSequenceNumbersSize = available;
         size_t i = 0;
         UA_NotificationMessageEntry *nme;

+ 1 - 1
src/server/ua_subscription_datachange.c

@@ -312,7 +312,7 @@ UA_MonitoredItem_SampleCallback(UA_Server *server,
     /* Stack-allocate some memory for the value encoding. We might heap-allocate
      * more memory if needed. This is just enough for scalars and small
      * structures. */
-    UA_Byte *stackValueEncoding = (UA_Byte *)UA_alloca(UA_VALUENCODING_MAXSTACK);
+    UA_STACKARRAY(UA_Byte, stackValueEncoding, UA_VALUENCODING_MAXSTACK);
     UA_ByteString valueEncoding;
     valueEncoding.data = stackValueEncoding;
     valueEncoding.length = UA_VALUENCODING_MAXSTACK;

+ 6 - 4
src/ua_securechannel.c

@@ -147,8 +147,9 @@ UA_SecureChannel_generateLocalKeys(const UA_SecureChannel *const channel,
         cryptoModule->encryptionAlgorithm.getLocalBlockSize(securityPolicy, channel->channelContext);
     size_t signingKeyLength =
         cryptoModule->signatureAlgorithm.getLocalKeyLength(securityPolicy, channel->channelContext);
-    const size_t buffSize = encryptionBlockSize + signingKeyLength + encryptionKeyLength;
-    UA_ByteString buffer = {buffSize, (UA_Byte *)UA_alloca(buffSize)};
+    const size_t bufSize = encryptionBlockSize + signingKeyLength + encryptionKeyLength;
+    UA_STACKARRAY(UA_Byte, bufBytes, bufSize);
+    UA_ByteString buffer = {bufSize, bufBytes};
 
     /* Local keys */
     UA_StatusCode retval = symmetricModule->generateKey(securityPolicy, &channel->remoteNonce,
@@ -180,8 +181,9 @@ UA_SecureChannel_generateRemoteKeys(const UA_SecureChannel *const channel,
         cryptoModule->encryptionAlgorithm.getRemoteBlockSize(securityPolicy, channel->channelContext);
     size_t signingKeyLength =
         cryptoModule->signatureAlgorithm.getRemoteKeyLength(securityPolicy, channel->channelContext);
-    const size_t buffSize = encryptionBlockSize + signingKeyLength + encryptionKeyLength;
-    UA_ByteString buffer = {buffSize, (UA_Byte *)UA_alloca(buffSize)};
+    const size_t bufSize = encryptionBlockSize + signingKeyLength + encryptionKeyLength;
+    UA_STACKARRAY(UA_Byte, bufBytes, bufSize);
+    UA_ByteString buffer = {bufSize, bufBytes};
 
     /* Remote keys */
     UA_StatusCode retval = symmetricModule->generateKey(securityPolicy, &channel->localNonce,

+ 1 - 1
src/ua_types.c

@@ -540,7 +540,7 @@ computeStrides(const UA_Variant *v, const UA_NumericRange range,
      * the bounds of the array. The Server shall return a partial result if some
      * elements exist within the range. */
     size_t count = 1;
-    UA_UInt32 *realmax = (UA_UInt32*)UA_alloca(sizeof(UA_UInt32) * dims_count);
+    UA_STACKARRAY(UA_UInt32, realmax, dims_count);
     if(range.dimensionsSize != dims_count)
         return UA_STATUSCODE_BADINDEXRANGENODATA;
     for(size_t i = 0; i < dims_count; ++i) {

+ 2 - 2
tools/nodeset_compiler/backend_open62541_nodes.py

@@ -303,13 +303,13 @@ def generateValueCodeDummy(dataTypeNode, parentNode, nodeset, bootstrapping=True
     typeStr = "UA_" + typeBrowseNode
 
     if parentNode.valueRank > 0:
-        code.append(typeStr + " *" + valueName + " = (" + typeStr + "*) UA_alloca(" + typeArr + ".memSize * " + str(parentNode.valueRank) + ");")
+        code.append("UA_STACKARRAY(" + typeStr + ", " + valueName + "," + str(parentNode.valueRank) + ");")
         for i in range(0, parentNode.valueRank):
             code.append("UA_init(&" + valueName + "[" + str(i) + "], &" + typeArr + ");")
             code.append("UA_Variant_setArray(&attr.value, " + valueName + ", (UA_Int32) " +
                         str(parentNode.valueRank) + ", &" + typeArr + ");")
     else:
-        code.append("void *" + valueName + " = UA_alloca(" + typeArr + ".memSize);")
+        code.append("UA_STACKARRAY(" + typeStr + ", " + valueName + ", 1);")
         code.append("UA_init(" + valueName + ", &" + typeArr + ");")
         code.append("UA_Variant_setScalar(&attr.value, " + valueName + ", &" + typeArr + ");")