Skip to content

Struct inputs to a variadic function written in C from ST behave unexpectedly #1553

@Angus-Bethke-Bachmann

Description

@Angus-Bethke-Bachmann

Describe the bug
When attempting to pass structs to a variadic function from an ST application to a C application (by means of a linked header: PLI <-> H) the structs are not extracted from the C va_arg macro in the correct manner.

The behaviour from C to C and ST to ST works as expected.

To Reproduce
Steps to reproduce the behaviour:
Create the below application (the C files should be compiled into a library "so"), then compile and run it with rusty.

The ST application:
colour_tracker_prog.st

FUNCTION main
VAR
    ciRed : ColourInfo;
    ciGreen : ColourInfo;
    ciBlue : ColourInfo;
END_VAR
    ciRed.primaryColour := red;
    ciRed.timesPicked := 5;

    ciGreen.primaryColour := green;
    ciGreen.timesPicked := 4;

    ciBlue.primaryColour := blue;
    ciBlue.timesPicked := 6;

    // Print output
    PrintStatistics(3, ciRed, ciGreen, ciBlue);
END_FUNCTION

colour_tracker.pli

VAR_GLOBAL
    globalCounter: INT;
END_VAR

TYPE RGB: (
        red,
        green,
        blue
    );
END_TYPE

TYPE ColourInfo:
    STRUCT
        timesPicked : DINT;
        primaryColour : RGB;
        extra: DINT;
    END_STRUCT
END_TYPE

FUNCTION PrintStatistics
VAR_INPUT
    argumentCount: DINT;
    colours: ColourInfo...;
END_VAR
END_FUNCTION

FUNCTION TestPrinter
END_FUNCTION

FUNCTION PrintColourInfo
VAR_INPUT
    colourInfo: ColourInfo;
END_VAR
END_FUNCTION

The C Library:
colour_tracker.h

#ifndef COLOUR_TRACKER
#define COLOUR_TRACKER

typedef enum eRGB {
    red = 0,
    green,
    blue
} RGB;

typedef struct {
    int32_t timesPicked;
    RGB primaryColour;
    int32_t extra;
} ColourInfo;

extern int16_t globalCounter;

void PrintStatistics(int32_t argumentCount, ...);

void PrintColourInfo(ColourInfo* colourInfo);

#endif /* !COLOUR_TRACKER */

colour_tracker.c

#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include "colour_tracker.h"

int16_t globalCounter = 0;

void PrintStatistics(int32_t argumentCount, ...) {
    va_list args;
    va_start(args, argumentCount);
    ColourInfo colourInfo;

    for (int i = 0; i < argumentCount; i++) {
        colourInfo = va_arg(args, ColourInfo);

        PrintColourInfo(&colourInfo);

        globalCounter++;
    }

    va_end(args);

    printf("Global Count: %d\n", globalCounter);
}

void PrintColourInfo(ColourInfo* colourInfo) {
    switch(colourInfo->primaryColour) {
        case red: printf("Red, Times Picked: %d\n", colourInfo->timesPicked); break;
        case green: printf("Green, Times Picked: %d\n", colourInfo->timesPicked); break;
        case blue: printf("Blue, Times Picked: %d\n", colourInfo->timesPicked); break;
        default: break;
    }
}

The output from the above application:

Red, Times Picked: 5
Red, Times Picked: 0
Red, Times Picked: 0
Global Count: 3

Expected behavior
I expect that when the above application is run, I get the following output:

Red, Times Picked: 5
Green, Times Picked: 4
Blue, Times Picked: 6
Global Count: 3

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions