nanopb/protobuf - how to force max size serialization/encoding - c

Documentation for pb_ostream_from_buffer says
After writing, you can check stream.bytes_written to find out how much
valid data there is in the buffer. This should be passed as the
message length on decoding side.
So ideally, when I send the serialized data I need to also send the bytes_written as a parameter separate from the buffer.
The problem is that my interface only allows me to send one variable: the buffer.
QUESTION
How do I specify always serialize the struct with no optimizations so that bufsize in
pb_istream_from_buffer(const pb_byte_t *buf, size_t bufsize)
can be a constant (i.e. the macro that specifies the maximum size) instead of needing to pass stream.bytes_written?

According to the Protocol Buffers encoding specification there are variable size types (like int32, int64, string, etc) and fixed size types (like fixed32, fixed64, double, etc). Now, this variable size encoding is more than just an optimization, it's a part of the design and specification. So disabling this "optimization" by the means of Protocol Buffers is only possible if your data consists exclusively of fixed length types and has no repeated fields as long as the number of repetitions is not fixed. I presume that this is not the case, since you're asking this question. So the short answer is no, it's not possible by means of the library because it would violate the encoding specification.
But in my opinion the desired effect could be easily achieved by encoding the size into the buffer with little CPU and RAM overhead. I presume you know the maximum size of the message generated by nanopb, we denote it by MAX_MSG_SIZE. We call this message the payload message. Suppose that this MAX_MSG_SIZE can be represented by some integer type, which we denote by wrapped_size_t (e.g. uint16_t).
The idea is simple:
allocate the buffer slightly larger than MAX_MSG_SIZE;
write the payload message generated by nanopb at some offset into the allocated buffer;
use this offset to encode the size of the payload message at the beginning of the buffer;
transmit the whole buffer having the fixed size equal to MAX_MSG_SIZE + sizeof(wrapped_size_t) to the receiver;
upon reception decode the size of the payload message and pass both the decoded size and the payload message to pb_istream_from_buffer.
I attach the code to illustrate the idea. I used an example from nanopb repository:
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include <pb_encode.h>
#include <pb_decode.h>
#include "simple.pb.h"
//#define COMMON_ENDIANNES
#ifdef COMMON_ENDIANNES
#define encode_size encode_size_ce
#define decode_size decode_size_ce
#else
#define encode_size encode_size_le
#define decode_size decode_size_le
#endif
typedef uint16_t wrapped_size_t;
/* Maximum size of the message returned by bytes_written */
const size_t MAX_MSG_SIZE = 11;
/* Size of the field storing the actual size of the message
* (as returned by bytes_written) */
const size_t SIZE_FIELD = sizeof(wrapped_size_t);
/* Fixed wrapped message size */
const size_t FIXED_MSG_SIZE = MAX_MSG_SIZE + sizeof(wrapped_size_t);
void print_usage(char *prog);
/* Get the address of the payload buffer from the transmitted buffer */
uint8_t* payload_buffer(uint8_t *buffer);
/* Encode the payload size into the transmitted buffer (common endiannes) */
void encode_size_ce(uint8_t *buffer, size_t size);
/* Decode the payload size into the transmitted buffer (common endiannes) */
wrapped_size_t decode_size_ce(uint8_t *buffer);
/* Encode the payload size into the transmitted buffer (little endian) */
void encode_size_le(uint8_t *buffer, size_t size);
/* Decode the payload size into the transmitted buffer (little endian) */
size_t decode_size_le(uint8_t *buffer);
int main(int argc, char* argv[])
{
/* This is the buffer where we will store our message. */
uint8_t buffer[MAX_MSG_SIZE + sizeof(wrapped_size_t)];
bool status;
if(argc > 2 || (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))))
{
print_usage(argv[0]);
return 1;
}
/* Encode our message */
{
/* Allocate space on the stack to store the message data.
*
* Nanopb generates simple struct definitions for all the messages.
* - check out the contents of simple.pb.h!
* It is a good idea to always initialize your structures
* so that you do not have garbage data from RAM in there.
*/
SimpleMessage message = SimpleMessage_init_zero;
/* Create a stream that will write to our buffer. */
pb_ostream_t stream = pb_ostream_from_buffer(payload_buffer(buffer),
MAX_MSG_SIZE);
if(argc > 1)
sscanf(argv[1], "%" SCNd32, &message.lucky_number);
else
{
printf("Input lucky number: ");
scanf("%" SCNd32, &message.lucky_number);
}
/* Encode the payload message */
status = pb_encode(&stream, SimpleMessage_fields, &message);
/* Wrap the payload, i.e. add the size to the buffer */
encode_size(buffer, stream.bytes_written);
/* Then just check for any errors.. */
if (!status)
{
printf("Encoding failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
}
/* Now we could transmit the message over network, store it in a file, etc.
* Note, the transmitted message has a fixed length equal to FIXED_MSG_SIZE
* and is stored in buffer
*/
/* But for the sake of simplicity we will just decode it immediately. */
{
/* Allocate space for the decoded message. */
SimpleMessage message = SimpleMessage_init_zero;
/* Create a stream that reads from the buffer. */
pb_istream_t stream = pb_istream_from_buffer(payload_buffer(buffer),
decode_size(buffer));
/* Now we are ready to decode the message. */
status = pb_decode(&stream, SimpleMessage_fields, &message);
/* Check for errors... */
if (!status)
{
printf("Decoding failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
/* Print the data contained in the message. */
printf("Your lucky number was %d; payload length was %d.\n",
(int)message.lucky_number, (int)decode_size(buffer));
}
return 0;
}
void print_usage(char *prog)
{
printf("usage: %s [<lucky_number>]\n", prog);
}
uint8_t* payload_buffer(uint8_t *buffer)
{
return buffer + SIZE_FIELD;
}
void encode_size_ce(uint8_t *buffer, size_t size)
{
*(wrapped_size_t*)buffer = size;
}
wrapped_size_t decode_size_ce(uint8_t *buffer)
{
return *(wrapped_size_t*)buffer;
}
void encode_size_le(uint8_t *buffer, size_t size)
{
int i;
for(i = 0; i < sizeof(wrapped_size_t); ++i)
{
buffer[i] = size;
size >>= 8;
}
}
size_t decode_size_le(uint8_t *buffer)
{
int i;
size_t ret = 0;
for(i = sizeof(wrapped_size_t) - 1; i >= 0; --i)
ret = buffer[i] + (ret << 8);
return ret;
}
UPD Ok, if, for some reason, you still wish to stick to the original GPB encoding there's another option available: fill the unused part of the buffer (i.e. the part after the last byte written by nanopb) with some valid data which will be ignored. For instance, you can reserve a field number which doesn't mark any field in your *.proto file but is used to mark the data which will be discarded by the GPB decoder. Let's denote this reserved field number as RESERVED_FIELD_NUMBER. This is used for backward compatibility but you can use it for your purpose as well. Let's call this filling-in the buffer with the dummy data sealing (perhaps there's a better term). This method also requires that you have at least 2 free bytes available to you after pb_encode.
So the idea of sealing is even simpler:
calculate how many buffer bytes is left unfilled after pb_encode;
mark the rest of the buffer as array of bytes with RESERVED_FIELD_NUMBER.
I attach the updated code, the main function is bool seal_buffer(uint8_t *buffer, size_t size), call it after pb_encode to seal the buffer and you're done. Currently, it has a limitation of sealing no more than 2 ** 28 + 4 bytes, but it could be easily updated to overcome this limitation.
#include <stdio.h>
#include <assert.h>
#include <inttypes.h>
#include <pb_encode.h>
#include <pb_decode.h>
#include "simple.pb.h"
/* Reserved field_number shouldn't be used for field numbering. We use it
* to mark the data which will be ignored upon reception by GPB parser.
* This number should be 1 to 15 to fit into a single byte. */
const uint8_t RESERVED_FIELD_NUMBER = 15;
/* Maximum size of the message returned by bytes_written (payload size) */
const size_t MAX_MSG_SIZE = 200;
/* Size of the transmitted message (reserve 2 bytes for minimal sealing) */
const size_t FIXED_MSG_SIZE = MAX_MSG_SIZE + 2;
void print_usage(char *prog);
/* Sealing the buffer means filling it in with data which is valid
* in the sense that a GPB parser accepts it as valid but ignores it */
bool seal_buffer(uint8_t *buffer, size_t size);
int main(int argc, char* argv[])
{
/* This is the buffer where we will store our message. */
uint8_t buffer[FIXED_MSG_SIZE];
bool status;
if(argc > 2 || (argc == 2 && (!strcmp(argv[1], "-h") || !strcmp(argv[1], "--help"))))
{
print_usage(argv[0]);
return 1;
}
/* Encode our message */
{
/* Allocate space on the stack to store the message data.
*
* Nanopb generates simple struct definitions for all the messages.
* - check out the contents of simple.pb.h!
* It is a good idea to always initialize your structures
* so that you do not have garbage data from RAM in there.
*/
SimpleMessage message = SimpleMessage_init_zero;
/* Create a stream that will write to our buffer. */
pb_ostream_t stream = pb_ostream_from_buffer(buffer, sizeof(buffer));
if(argc > 1)
sscanf(argv[1], "%" SCNd32, &message.lucky_number);
else
{
printf("Input lucky number: ");
scanf("%" SCNd32, &message.lucky_number);
}
/* Now we are ready to encode the message! */
status = pb_encode(&stream, SimpleMessage_fields, &message);
/* Then just check for any errors.. */
if (!status)
{
fprintf(stderr, "Encoding failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
/* Now the main part - making the buffer fixed-size */
assert(stream.bytes_written + 2 <= FIXED_MSG_SIZE);
if(!seal_buffer(buffer + stream.bytes_written,
FIXED_MSG_SIZE - stream.bytes_written))
{
fprintf(stderr, "Failed sealing the buffer "
"(filling in with valid but ignored data)\n");
return 1;
}
}
/* Now we could transmit the message over network, store it in a file or
* wrap it to a pigeon's leg.
*/
/* But because we are lazy, we will just decode it immediately. */
{
/* Allocate space for the decoded message. */
SimpleMessage message = SimpleMessage_init_zero;
/* Create a stream that reads from the buffer. */
pb_istream_t stream = pb_istream_from_buffer(buffer, FIXED_MSG_SIZE);
/* Now we are ready to decode the message. */
status = pb_decode(&stream, SimpleMessage_fields, &message);
/* Check for errors... */
if (!status)
{
fprintf(stderr, "Decoding failed: %s\n", PB_GET_ERROR(&stream));
return 1;
}
/* Print the data contained in the message. */
printf("Your lucky number was %d.\n", (int)message.lucky_number);
}
return 0;
}
void print_usage(char *prog)
{
printf("usage: %s [<lucky_number>]\n", prog);
}
bool seal_buffer(uint8_t *buffer, size_t size)
{
size_t i;
if(size == 1)
{
fprintf( stderr, "Cannot seal the buffer, at least 2 bytes are needed\n");
return false;
}
assert(size - 5 < 1<<28);
if(size - 5 >= 1<<28)
{
fprintf( stderr, "Representing the size exceeding 2 ** 28 + 4, "
"although it's not difficult, is not yet implemented\n");
return false;
}
buffer[0] = (15 << 3) + 2;
/* encode the size */
if(size - 2 < 1<<7)
buffer[1] = size - 2;
else
{
/* Size is large enough to fit into 7 bits (1 byte).
* For simplicity we represent the remaining size by 4 bytes (28 bits).
* Note that 1 byte is used for encoding field_number and wire_type,
* plus 4 bytes for the size encoding, therefore the "remaining size"
* is equal to (size - 5)
*/
size -= 5;
for(i = 0; i < 4; ++i)
{
buffer[i + 1] = i < 3? (size & 0x7f) | 0x80: size & 0x7f;
size >>= 7;
}
}
return true;
}

Related

Realloc fails without any particular reason

I am trying to solve a "suppose to be" a simple C question.
Q: Receive "infinite" input by user using int pointer until EOF received using malloc and realloc.
I defined a int pointer like this:
int *inputBuffer = NULL;
and initialized it using this method:
/* #define BUFFER_SIZE 8 - already defined at top of code, posted here for more info */
/* Creates buffer by using malloc -
if succeded returns true, otherwise false */
int createBuffer(int **inputBuffer)
{
*inputBuffer = (int*) calloc(BUFFER_SIZE, sizeof(char)); /* Allocate memory to get input from user */
if(*inputBuffer == NULL)
return FALSE;
return TRUE;
}
by calling createBuffer(&inputBuffer)
so far so good, memory is allocated successfully.
before starting to receive characters from user I defined the following properties:
int totalCharacters = 0;
int bufferExtendsCounter = 1;
int character;
Next step is to receive characters inputs from user like this:
/* #define MEMORY_SAFE_GAP 4 - already defined at top of code, posted here for more info */
while((character = getchar()) != EOF && inputBuffer != NULL)
{
/* Check if reallocate needs to be called since almost maxed out buffer */
if(totalCharacters - MEMORY_SAFE_GAP > (BUFFER_SIZE * bufferExtendsCounter))
{
/* Add 1 to extends buffer times */
bufferExtendsCounter+=1;
if(!extendBuffer(&inputBuffer, totalCharacters))
printf("\nFailed to allocate more memory.");
}
/* Initialize buffer with character, this is safe since there is a memory safe gap */
inputBuffer[totalCharacters] = character;
totalCharacters++;
}
extend buffer looks like this:
/* Extends buffer size by using realloc
if succeded returns true, otherwise false */
int extendBuffer(int **inputBuffer, int minimumBufferSize)
{
/* Check how many times buffer needs to be multiple (at least) */
int multipleBufferNumber = (minimumBufferSize / BUFFER_SIZE) + 1;
int newBufferSize = BUFFER_SIZE * multipleBufferNumber * sizeof(char);
while(newBufferSize < minimumBufferSize)
{
multipleBufferNumber+=1;
newBufferSize = BUFFER_SIZE * multipleBufferNumber * sizeof(char);
}
/* Reallocate memory for next chunck of data */
*inputBuffer = realloc(*inputBuffer, newBufferSize);
/* Check if memory successfully allocated */
if(*inputBuffer == NULL)
return FALSE;
return TRUE;
}
It looks like I extend the buffer size enough for more input by user, but still gets error:
corrupted size vs. prev_size: 0x08f86010 ***
Example input:
TestProgramTest (Pressed Enter after last 't')
(DebugPrint: Received 13 characters)
(DebugPrint: Reallocating to size 16)
*** Error in `./test': corrupted size vs. prev_size: 0x08f86010 ***
EDIT (Due to lack of code parts):
The following part is right after while loop:
inputBuffer[totalCharacters] = '\0';
printf("\nInput by user:\n");
/* #define LINE_LENGTH 5 - already defined at top of code, posted here for more info */
printBuffer(inputBuffer, LINE_LENGTH, totalCharacters);
/* free memory */
free(inputBuffer);
and printBuffer looks like:
/* Prints the buffer data to pretty output */
void printBuffer(int *inputBuffer, int lineLength, int totalCharacters)
{
int i;
for(i = 0; i < totalCharacters; i++)
{
/* Print each char value */
printf("%c", inputBuffer[i]);
/* Check if got to line limit, if so enter new line */
if((i+1) % lineLength == 0)
printf("\n");
}
}
Second edit:
Changed all int pointer parts to char pointer.
Full code looks like:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#define LINE_LENGTH 5
#define BUFFER_SIZE 8
#define TRUE 1
#define FALSE 0
#define MEMORY_SAFE_GAP 4
int createBuffer(char **inputBuffer);
int extendBuffer(char **inputBuffer, int minimumBufferSize);
void printBuffer(char *inputBuffer, int lineLength, int totalCharacters);
int main(void)
{
char *inputBuffer = NULL;
if(!createBuffer(&inputBuffer))
{
printf("Memory cannot be allocated, program will exit now.");
exit(-1);
}
int totalCharacters = 0;
int bufferExtendsCounter = 1;
char character;
printf("Please enter a string:\n");
/* Loop till EOF received */
while((character = getchar()) != EOF && inputBuffer != NULL)
{
/* Check if reallocate needs to be called since almost maxed out buffer */
if(totalCharacters - MEMORY_SAFE_GAP > (BUFFER_SIZE * bufferExtendsCounter))
{
/* Add 1 to extends buffer times */
bufferExtendsCounter+=1;
if(!extendBuffer(&inputBuffer, totalCharacters))
printf("\nFailed to allocate more memory.");
}
/* Initialize buffer with character, this is safe since there is a memory safe gap */
inputBuffer[totalCharacters] = character;
totalCharacters++;
}
inputBuffer[totalCharacters] = '\0';
printBuffer(inputBuffer, LINE_LENGTH, totalCharacters);
/* free memory */
free(inputBuffer);
return 0;
}
/* Creates buffer by using malloc
if succeded returns true, otherwise false */
int createBuffer(char **inputBuffer)
{
/* Allocate memory to get input from user */
*inputBuffer = (char*) calloc(BUFFER_SIZE, sizeof(char));
if(*inputBuffer == NULL)
return FALSE;
return TRUE;
}
/* Extends buffer size by using realloc
if succeded returns true, otherwise false */
int extendBuffer(char **inputBuffer, int minimumBufferSize)
{
/* Check how many times buffer needs to be multiple (at least) */
int multipleBufferNumber = (minimumBufferSize / BUFFER_SIZE) + 1;
int newBufferSize = BUFFER_SIZE * multipleBufferNumber * sizeof(char);
while(newBufferSize < minimumBufferSize)
{
multipleBufferNumber+=1;
newBufferSize = BUFFER_SIZE * multipleBufferNumber * sizeof(char);
}
/* Reallocate memory for next chunck of data */
*inputBuffer = realloc(*inputBuffer, newBufferSize);
/* Check if memory successfully allocated */
if(*inputBuffer == NULL)
return FALSE;
return TRUE;
}
/* Prints the buffer data to pretty output */
void printBuffer(char *inputBuffer, int lineLength, int totalCharacters)
{
printf("Printing buffer\n");
int i;
for(i = 0; i < totalCharacters; i++)
{
/* Print each char value */
printf("%c", inputBuffer[i]);
/* Check if got to line limit, if so enter new line */
if((i+1) % lineLength == 0)
printf("\n");
}
}
Any help would be great!
Thanks in advance.
Right here
*inputBuffer = (int*) calloc(BUFFER_SIZE, sizeof(char));
You reserve space for 8 chars but try to store 8 ints in it
Why isnt inputBuffer just a char*? since thats what you are storing
Now you have fixed that - look at this
if (totalCharacters - MEMORY_SAFE_GAP > (BUFFER_SIZE * bufferExtendsCounter))
I do not know what the intention of the 'MEMORY_SAFE_GAP' is but its wrong
Look at what happens when I input character number 8
if(8 - 4 > 8 * 1)
is false, so you do not extend the buffer.
This 'SAFE-GAP ensure that you always run off the end, your code no longer crashes if you just have
if (totalCharacters >= (BUFFER_SIZE * bufferExtendsCounter))
output is still a little garbled but you can probably fix that. I input 1234567890 and got
Please enter a string:
1234567890
^Z
Printing buffer
12345
678═0

How to send and receive data through UART between two Arduino Unos

I have been working through this problem for quite some time now and have succeeded in getting a partial mark. I would like to know what is wrong with the code that I have, that is preventing me from succeeding under certain conditions
I need one arduino to communicate with another one by sending a string of characters. So far I have succeeded in sending and receiving some data but think that I may be having an issue with the buffer I have set up in my uart_receive_string() function. I will provide all of the necessary information and code needed in order to test this, just let me know if any more info is required and Ill be happy to provide.
Here is a link to the tinkercad driver: https://www.tinkercad.com/things/eUZqkaIHp6J
Just click "Copy and Tinker" and hit the code button up top in order to paste the below code into it. You will need to paste the code into both ardunios by selecting them via the drop down box.
This is the criteria for the question I am working on:
This is the output I should receive in the test driver provided:
Here is the current code that I have implemented:
It is what needs to be copied into tinkercad for both arduino's
#include <stdint.h>
#include <stdio.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
void uart_putbyte(unsigned char data);
int uart_getbyte(unsigned char *buffer);
/*
** Define a function named uart_send_string which transmits the contents of
** a standard C string (i.e. a null-terminated char array) over UART. The
** function should iterate over the characters in the array, using a cast to
** convert each to an unsigned char, and transmitting the resulting byte via
** uart_putbyte. The end of the string should be signalled by sending a single
** null byte. That is, the number 0, not the character '0'.
**
** Param: str - string to be transmitted.
**
** Returns: Nothing.
*/
// vvvvvvv I need help with this vvvvvvv
void uart_send_string(char str[])
{
int i = 0;
char ch;
do{
ch = str[i];
uart_putbyte(ch);
i++;
}while(ch != '\0');
}
/*
** Define a function named uart_receive_string which uses uart_getbyte to fetch
** the contents of a standard C string (i.e. a null-terminated char array)
** from UART. The function should wait for characters, and must not return
** until a complete string has been retrieved.
**
** Note that uart_getbyte will return 1 if a byte is available, and zero
** otherwise. Therefore, to fetch a byte and store it in a variable named x,
** you will need to use a construct of the form:
** unsigned char x;
** while (! uart_getbyte(&x)) {
** // Do nothing.
** }
**
** Param: buffer - a char array which has capacity to store a string
** containing at most (buff_len-1) characters. If more than (buff_len-1)
** characters are received, the first (buff_len-1) of them should be
** stored consecutively in the buffer, and any others discarded. The
** string must be terminated correctly with a null terminator in all
** circumstances.
**
** Param: buff_len - an int which specifies the capacity of the buffer.
**
** Returns: Nothing. However, up to buff_len elements of buffer may have been
** overwritten by incoming data.
*/
//vvvvvvv I need help with this vvvvvvv
void uart_receive_string(char buffer[], int buff_len)
{
int i = 0;
unsigned char ch;
while(!uart_getbyte(&ch))
{
if(ch == 0)
{
break;
}
if(i < buff_len-1)
{
ch = buffer[i];
uart_putbyte(ch);
i++;
}
}
buffer[i]=0;
}
/*
***************************************************************************
** Initialise UART.
***************************************************************************
*/
void uart_init(void) {
UBRR0 = F_CPU / 16 / 9600 - 1;
UCSR0A = 0;
UCSR0B = (1 << RXEN0) | (1 << TXEN0);
UCSR0C = (3 << UCSZ00);
}
/*
**************************************************************************
** Send one byte, protecting against overrun in the transmit buffer.
**
** Param: data - a byte to be transmitted.
**
** Returns: Nothing.
***************************************************************************
*/
#ifndef __AMS__
void uart_putbyte(unsigned char data) {
// Wait for empty transmit buffer
while (!(UCSR0A & (1 << UDRE0)));
// Send data by assigning into UDR0
UDR0 = data;
}
#endif
/*
***************************************************************************
** Attempt to receive one byte, returning immediately to sender.
**
** Param: buffer - the address of a byte in which a result may be stored.
**
** Returns: If a byte is available returns 1 and stores the incoming byte in
** location referenced by buffer. Otherwise returns 0 and makes no other
** change to the state.
***************************************************************************
*/
#ifndef __AMS__
int uart_getbyte(unsigned char *buffer) {
// If receive buffer contains data...
if (UCSR0A & (1 << RXC0)) {
// Copy received byte from UDR0 into memory location (*buffer)
*buffer = UDR0;
//
return 1;
}
else {
return 0;
}
}
#endif
/*
***************************************************************************
** Implement main event loop.
***************************************************************************
*/
void process() {
// Use two devices, as indicated in the supplied TinkerCad model. One
// device acts as the sender (is_sender = 1), the other as receiver
// (is_sender = 0). Change this to set the role accordingly.
const int is_sender = 1;
if (is_sender) {
static char * messages_to_send[] = {
"", // Empty string
"A", // String with one symbol.
"Hello from CAB202!", // Multiple symbols
"1234567890abcdefghijklmnopqrstuvwxyz", // Longer than buffer size.
NULL, // End of list
};
static int next_message = 0;
uart_send_string(messages_to_send[next_message]);
next_message ++;
if (messages_to_send[next_message] == NULL) next_message = 0;
_delay_ms(300);
}
else {
#define BUFF_SIZE 20
char buffer[BUFF_SIZE];
uart_receive_string(buffer, BUFF_SIZE);
uart_send_string(buffer);
uart_putbyte('\r');
uart_putbyte('\n');
}
}
int main(void) {
uart_init();
while (1) {
process();
}
return 0;
}
The areas of this code that I am required to work on are these:
This is needed to send the data:
void uart_send_string(char str[])
{
int i = 0;
char ch;
do{
ch = str[i];
uart_putbyte(ch);
i++;
}while(ch != '\0');
}
This is needed to receive the data:
void uart_receive_string(char buffer[], int buff_len)
{
int i = 0;
unsigned char ch;
while(!uart_getbyte(&ch))
{
if(ch == 0)
{
break;
}
if(i < buff_len-1)
{
ch = buffer[i];
uart_putbyte(ch);
i++;
}
}
buffer[i]=0;
}
I am really sorry if this is hard to understand. Ill do my best to clarify any additional information that is needed. I just need to figure out what I am doing incorrectly.

LWIP ECHO SERVER: How to increase the buffer size in itoa function?

I am working with Xilinx Ethernetlite (LWIP) design. I am able to transfer the data from KC board to PC (Hercules) through Ethernet only if buf =32. But my actual buffer size is 1024. How to increase the buffer size from 32 to 1024
I am unable to make sure whether the mistake is in code or in hercules. To read the values (integer) in hercules i am doing this function.
initially, From hercules i will send the Hello command to Board,then board with accept that request. After that, board will output the data (integer values) to Hercules.
C code for itoa
char* itoa(int val, int base)
{
static char buf[32] = {0}; //buf size
int i = 30;
for(; val && i ; --i, val /= base)
buf[i] = "0123456789abcdef"[val % base];
return &buf[i+1];
}
Modified code
#define DAQ_FIFO_DEPTH 128
int transfer_data()
{
return 0;
}
err_t tcp_write_u32_string(struct tcp_pcb *pcb, unsigned char prefix, u32_t value)
{
unsigned char buf[11]; /* enough room for prefix and value. */
err_t result;
u16_t len;
unsigned char *p = buf + sizeof buf;
do {
/* ASCII encoding: '0' = 48, '1' = 49, ..., '9' = 57. */
*(--p) = 48 + (value % 10u);
value /= 10;
} while (value);
if (prefix)
*(--p) = prefix;
len = buf + sizeof buf - p;
if (tcp_sndbuf(pcb) < len)
{
result = tcp_output(pcb);
if (result != ERR_OK)
return result;
}
return tcp_write(pcb, p, len, TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
}
err_t send_list(struct tcp_pcb *pcb, const u32_t data[], u16_t len)
{
static const char newline[2] = { 13, 10 }; /* ASCII \r\n */
err_t result;
if (len > 0) {
u16_t i;
result = tcp_write_u32_string(pcb, 0, data[0]);
if (result != ERR_OK)
return result;
for (i = 1; i < len; i++)
{
/* ASCII comma is code 44. (Use 32 for space, or 9 for tab.) */
result = tcp_write_u32_string(pcb, 44, data[i]);
if (result != ERR_OK)
return result;
}
}
result = tcp_write(pcb, newline, 2, 0);
if (result)
return result;
return tcp_output(pcb);
}
int application_connection(void *arg, struct tcp_pcb *conn, err_t err)
{
struct netif *netif = arg; /* Because of tcp_arg(, netif). */
u32_t data[DAQ_FIFO_DEPTH];
u32_t i, n;
if (err != ERR_OK) {
tcp_abort(conn);
return ERR_ABRT;
}
err = daq_setup();
if (err != ERR_OK)
{
tcp_abort(conn);
return ERR_ABRT;
}
while (1)
{
xemacif_input(netif);
tcp_tmr();
tcp_output(conn);
n = daq_acquire(data, DAQ_FIFO_DEPTH);
if (n > DAQ_FIFO_DEPTH)
break;
if (tcp_write(conn, data, n * sizeof data[0], TCP_WRITE_FLAG_COPY) != ERR_OK)
break;
}
// daq_close();
/* Close the TCP connection. */
if (tcp_close(conn) == ERR_OK)
return ERR_OK;
/* Close failed. Abort it, then. */
tcp_abort(conn);
return ERR_ABRT;
}
int application_main(struct netif *netif, unsigned int port)
{
struct tcp_pcb *pcb;
err_t err;
pcb = tcp_new();
if (!pcb) {
/* Out of memory error */
return -1;
}
err = tcp_bind(pcb, IP_ADDR_ANY, port);
if (err != ERR_OK) {
/* TCP error */
return -1;
}
pcb = tcp_listen_with_backlog(pcb, 1);
if (!pcb) {
/* Out of memory. */
return -1;
}
tcp_arg(pcb, netif);
tcp_accept(pcb, application_connection);
while (1)
xemacif_input(netif);
}
Hercules output
enter image description here
So, this is a continuation from the discussion at Xilinx forums?
The itoa() function converts an unsigned integer (stored in an int) into the first 30 or so characters in the buffer buf.
The recv_callback() function makes little to no sense.
The call to aurora_rx_main() is documented as a "FUNCTION CALL", which is rather less than helpful (because we have no idea what it does), and even its return value is completely ignored.
The first for loop dumps the contents of the first 100 u32's in DestinationBuffer[] for debugging purposes, so that code is unrelated to the task at hand. However, we don't know who or what filled DestinationBuffer. It might or might not have been filled by the aurora_rx_main() call; we're not told either way.
(The tcp_*() functions seem to follow the API described in lwIP Wiki at Wikia.)
If the p parameter is NULL, then tcp_close(tcpb) is called, followed by a tcp_recv(tcpb, NULL) call. This makes the least sense of all: why try to receive anything (and why the NULL parameter) after a close?
The next part is similarly baffling. It looks like the if test checks if the TCP send buffer is over 1024 bytes in size. If not, the p buffer is freed. Otherwise, the for loop tries to convert each u32 in DestinationBuffer to a string, write that string to the TCP buffer; however, rather than the proper api flags, it uses the constant 1, and does not even check if appending to the TCP send buffer works.
In summary, this looks like a pile of copy-pasted code that does nothing sensible. Increasing the buffer size in itoa function is not only unnecessary (an u32, even when converted to an int, will always fit within 12 characters (excluding either the minus sign, or the nul byte at end, so make that 13 characters total), but completely unrelated to the problem it is supposed to fix.
The root problem is that the code is horrible. Modifying it is like putting car body filler over a piece of old chewing gum, in an effort to "fix" it. The proper fix is to rip out that junk code altogether, and use something better instead.
Edit: The OP states that they're a new programmer, so the comments above should be taken as a direct, honest opinion of the code shown, and not about OP themselves. Let's see if we can help OP produce better code.
First, the itoa() function shown is silly. Assuming the intent is really to send back the u32_ts in the DestinationBuffer as decimal strings, it is much better to implement a helper function for doing the conversion. Since the value is to be preceded with a comma (or some other separator), we can add that trivially as well. Since it will be sent using tcp_write(), we'll combine the functionality:
err_t tcp_write_u32_string(struct tcp_pcb *pcb,
unsigned char prefix, /* 0 for none */
u32_t value)
{
/* Because 0 <= u32_t <= 4294967295, the value itself is at most 10 digits long. */
unsigned char buf[11]; /* enough room for prefix and value. */
err_t result;
u16_t len;
unsigned char *p = buf + sizeof buf;
/* Construct the value first, from right to left. */
do {
/* ASCII encoding: '0' = 48, '1' = 49, ..., '9' = 57. */
*(--p) = 48 + (value % 10u);
value /= 10;
} while (value);
/* Prepend the prefix, if any. */
if (prefix)
*(--p) = prefix;
/* Calculate the length of this part. */
len = buf + sizeof buf - p;
/* If the TCP buffer does not have enough free space, flush it. */
if (tcp_sendbuf(pcb) < len) {
result = tcp_output(pcb);
if (result != ERR_OK)
return result;
}
/* Append the buffer to the TCP send buffer.
We also assume the packet is not done yet. */
return tcp_write(pcb, p, len, TCP_WRITE_FLAG_COPY | TCP_WRITE_FLAG_MORE);
}
so that to send num u32_ts from a specified array as decimal strings, with a newline at end, you could use
err_t send_list(struct tcp_pcb *pcb,
const u32_t data[],
u16_t len)
{
static const char newline[2] = { 13, 10 }; /* ASCII \r\n */
err_t result;
if (len > 0) {
u16_t i;
/* The first number has no prefix. */
result = tcp_write_u32_string(pcb, 0, data[0]);
if (result != ERR_OK)
return result;
/* The following numbers have a comma prefix. */
for (i = 1; i < len; i++) {
/* ASCII comma is code 44. (Use 32 for space, or 9 for tab.) */
result = tcp_write_u32_string(pcb, 44, data[i]);
if (result != ERR_OK)
return result;
}
}
/* We add a final newline.
Note that this one can be referenced,
and it does complete what we wanted to send thus far. */
result = tcp_write(pcb, newline, 2, 0);
if (result)
return result;
/* and flush the buffer, so the packet gets sent right now. */
return tcp_output(pcb);
}
Now, I haven't written C for Xilinx or used the lwIP stack at all, so the above code is written blind. Yet, I'm pretty confident it works (barring any typos or thinkos; if you find any, report them in a comment, and I'll verify and fix).
The two buffers (buf and newline) are declared static, so that although they're only visible within their respective functions, their value is valid in the global scope.
Because TCP is a stream protocol, it is not necessary to fit each response to a single packet. Other than the 11-character (for each number and its prefixing character) and the 2-character (newline) buffers, the only large buffer you need is the TCP send buffer (the maximum transmission unit or maximum segment size as I'm not sure how lwIP uses the buffer internally), typically between 536 and 1518 bytes.
The two above functions try to split packets between numbers, but that's just because it's easier than to try and fill each packet exactly. If the next (comma and) value fit in the buffer, then it is added to the buffer; otherwise the buffer is flushed first, and then the next (comma and) value added to the buffer.
From the recipient side, you should obtain a nice, readable stream using e.g. netcat. (I have no idea if Hercules is an application, or just the name of your local machine.) Because TCP is a stream protocol, the recipient cannot (reliably) detect where the packet boundaries were (unlike in, say, UDP datagrams). In practice, a TCP connection is just two streams of data, each going one way, and the split into packets is just a protocol detail application programmers don't need to worry about. For lwIP, because it is such a low-level library, a little bit of care need to be taken, but as one can see from the above code, it's really not that much.
In a comment, OP explained that they are not very experienced, and that the overall intent is to have the device accept a TCP connection, and stream data (samples acquired by a separate acquisition board) as unsigned 32-bit integers via the connection.
Because I would love to have one of those FPGA boards (I have several tasks I could see if I could offload to an FPGA), but no resources to get one, I shall try to outline the entire application here. Do note that the only information I have to go on, is the 2018 version of Xilinx OS and Libraries Document Collection (UG643) (PDF). It looks like OP wants to use the raw API, for high performance.
Converting the samples to text is silly, especially if high performance is desired. We should just use raw binary, and whatever endianness the KC705 uses. (I didn't see it at a quick glance from the documentation, but I suspect it is little-endian).
According to the documentation, the raw API main() is something similar to following:
int main(void)
{
/* MAC address. Use an unique one. */
unsigned char mac[6] = { 0x00, 0x0A, 0x35, 0x00, 0x01, 0x02 };
struct netif *netif = NULL;
ip_addr_t ipaddr, netmask, gateway;
/* Define IP address, netmask, and gateway. */
IP4_ADDR(&ipaddr, 192, 168, 1, 1);
IP4_ADDR(&netmask, 255, 255, 255, 0);
IP4_ADDR(&gateway, 0, 0, 0, 0);
/* Initialize lwIP networking stack. */
lwip_init();
/* Add this networking interface, and make it the default one */
if (!xemac_add(netif, &ipaddr, &netmask, &gateway, mac, EMAC_BASEADDR)) {
printf("Error adding network interface\n\r");
return -1;
}
netif_set_default(netif);
platform_enable_interrupts();
/* Bring the network interface up (activate it) */
netif_set_up(netif);
/* Our application listens on port 7. */
return application_main(netif, 7);
}
In the documentation examples, rather than return application_main(netif);, you'll see a call to start_application(), and then an infinite loop that regularly calls xemacif_input(netif) instead. It just means that out application_main() must call xemacif_input(netif) regularly, to be able to receive data. (The lwIP documentation says that we should also call sys_check_timeouts() or tcp_tmr() at regular intervals.)
Note that I've omitted error reporting printfs, and that rather than recovering from errors gracefully, this will just return (from main()); I'm not certain whether this causes the KC705 to restart or what.
int application_main(struct netif *netif, unsigned int port)
{
struct tcp_pcb *pcb;
err_t err;
pcb = tcp_new();
if (!pcb) {
/* Out of memory error */
return -1;
}
/* Listen for incoming connections on the specified port. */
err = tcp_bind(pcb, IP_ADDR_ANY, port);
if (err != ERR_OK) {
/* TCP error */
return -1;
}
pcb = tcp_listen_with_backlog(pcb, 1);
if (!pcb) {
/* Out of memory. */
return -1;
}
/* The accept callback function gets the network interface
structure as the extra parameter. */
tcp_arg(pcb, netif);
/* For each incoming connection, call application_connection(). */
tcp_accept(pcb, application_connection);
/* In the mean time, process incoming data. */
while (1)
xemacif_input(netif);
}
For each TCP connection to the port, we get a call to application_connection(). This is the function that sets up the data acquisition board, and transfers the data for as long as the recipient wants it.
/* How many DAQ samples to process in each batch.
* Should be around the DAQ FIFO depth or so, I think. */
#define DAQ_FIFO_DEPTH 128
err_t application_connection(void *arg, struct tcp_pcb *conn, err_t err)
{
struct netif *netif = arg; /* Because of tcp_arg(, netif). */
u32_t data[DAQ_FIFO_DEPTH];
u32_t i, n;
/* Drop the connection if there was an error. */
if (err != ERR_OK) {
tcp_abort(conn);
return ERR_ABRT;
}
/* Setup the data aquisition. */
err = daq_setup();
if (err != ERR_OK) {
tcp_abort(conn);
return ERR_ABRT;
}
/* Data acquisition to TCP loop. */
while (1) {
/* Keep the networking stack running. */
xemacif_input(netif);
tcp_tmr();
/* Tell the networking stack to output what it can. */
tcp_output(conn);
/* Acquire up to DAQ_FIFO_DEPTH samples. */
n = daq_acquire(data, DAQ_FIFO_DEPTH);
if (n > DAQ_FIFO_DEPTH)
break;
/* Write data as-is to the tcp buffer. */
if (tcp_write(conn, data, n * sizeof data[0], TCP_WRITE_FLAG_COPY) != ERR_OK)
break;
}
/* Stop data acquisition. */
daq_close();
/* Close the TCP connection. */
if (tcp_close(conn) == ERR_OK)
return ERR_OK;
/* Close failed. Abort it, then. */
tcp_abort(conn);
return ERR_ABRT;
}
There are three more functions to implement: daq_setup(), which should setup the data acquisition and FIFOs; daq_acquire(u32_t *data, u32_t count) that stores up to count samples to data[], and returns the actual number of samples stored -- it would be best if it just drained the FIFO, rather than waited for new samples to arrive --, and finally daq_close(), that stops the data acquisition.
I believe they should be something like this:
XLlFifo daq_fifo;
err_t daq_setup(void)
{
XLlFifo_Config *config = NULL;
config = XLlFifo_LookupConfig(DAQ_FIFO_ID);
if (!config)
return ERR_RTE;
if (XLlFifo_CfgInitialize(&daq_fifo, config, config->BaseAddress) != XST_SUCCESS)
return ERR_RTE;
}
u32_t daq_acquire(u32_t *data, u32_t max)
{
u32_t len, have;
have = XLlFifo_iRxGetLen(&daq_fifo);
if (have < 1)
return 0;
else
if (have < max)
max = have;
for (len = 0; len < max; len++)
data[len] = XLlFifo_RxGetWork(&daq_fifo);
return len;
}
err_t daq_close(void)
{
/* How to stop the FIFO? Do we need to? */
}
That's about it.

Stray characters seen at output of snprintf

I have a string creating function in C which accepts an array of structs as it's argument and outputs a string based on a predefined format (like a list of list in python).
Here's the function
typedef struct
{
PacketInfo_t PacketInfo;
char Gnss60[1900];
//and other stuff...
} Track_json_t;
typedef struct
{
double latitude;
double longitude;
} GPSPoint_t;
typedef struct
{
UInt16 GPS_StatusCode;
UInt32 fixtime;
GPSPoint_t point;
double altitude;
unsigned char GPS_Satilite_Num;
} GPS_periodic_t;
unsigned short SendTrack()
{
Track_json_t i_sTrack_S;
memset(&i_sTrack_S, 0x00, sizeof(Track_json_t));
getEvent_Track(&i_sTrack_S);
//Many other stuff added to the i_sTrack_S struct...
//Make a JSON format out of it
BuildTrackPacket_json(&i_sTrack_S, XPORT_MODE_GPRS);
}
Track_json_t *getEvent_Track(Track_json_t *trk)
{
GPS_periodic_t l_gps_60Sec[60];
memset(&l_gps_60Sec, 0x00,
sizeof(GPS_periodic_t) * GPS_PERIODIC_ARRAY_SIZE);
getLastMinGPSdata(l_gps_60Sec, o_gps_base);
get_gps60secString(l_gps_60Sec, trk->Gnss60);
return trk;
}
void get_gps60secString(GPS_periodic_t input[60], char *output)
{
int i = 0;
memcpy(output, "[", 1); ///< Copy the first char as [
char temp[31];
for (i = 0; i < 59; i++) { //Run for n-1 elements
memset(temp, 0, sizeof(temp));
snprintf(temp, sizeof(temp), "[%0.8f,%0.8f],",
input[i].point.latitude, input[i].point.longitude);
strncat(output, temp, sizeof(temp));
}
memset(temp, 0, sizeof(temp)); //assign last element
snprintf(temp, sizeof(temp), "[%0.8f,%0.8f]]",
input[i].point.latitude, input[i].point.longitude);
strncat(output, temp, sizeof(temp));
}
So the output of the function must be a string of format
[[12.12345678,12.12345678],[12.12345678,12.12345678],...]
But at times I get a string which looks like
[[12.12345678,12.12345678],[55.01[12.12345678,12.12345678],...]
[[21.28211567,84.13454083],[21.28211533,21.22[21.28211517,84.13454000],..]
Previously, I had a buffer overflow at the function get_gps60secString, I fixed that by using snprintf and strncat.
Note: This is an embedded application and this error occur once or twice a day (out of 1440 packets)
Question
1. Could this be caused by an interrupt during the snprintf/strncat process?
2. Could this be caused by a memory leak, overwriting the stack or some other segmentation issue caused else where?
Basically I would like to understand what might be causing a corrupt string.
Having a hard time finding the cause and fixing this bug.
EDIT:
I used chux's function. Below is the Minimal, Complete, and Verifiable Example
/*
* Test code for SO question https://stackoverflow.com/questions/5216413
* A Minimal, Complete, and Verifiable Example
*/
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <stdbool.h>
#include <signal.h>
#include <unistd.h>
typedef unsigned short UInt16;
typedef unsigned long UInt32;
#define GPS_PERIODIC_ARRAY_SIZE 60
#define GPS_STRING_SIZE 1900
/* ---------------------- Data Structs --------------------------*/
typedef struct
{
char Gnss60[GPS_STRING_SIZE];
} Track_json_t;
typedef struct
{
double latitude;
double longitude;
} GPSPoint_t;
typedef struct
{
UInt16 GPS_StatusCode;
UInt32 fixtime;
GPSPoint_t point;
double altitude;
unsigned char GPS_Satilite_Num;
} GPS_periodic_t;
/* ----------------------- Global --------------------------------*/
FILE *fptr; //Global file pointer
int res = 0;
int g_last = 0;
GPS_periodic_t l_gps_60Sec[GPS_PERIODIC_ARRAY_SIZE];
/* ----------------------- Function defs --------------------------*/
/* At signal interrupt this function is called.
* Flush and close the file. And safly exit the program */
void userSignalInterrupt()
{
fflush(fptr);
fclose(fptr);
res = 1;
exit(0);
}
/* #brief From the array of GPS structs we create a string of the format
* [[lat,long],[lat,long],..]
* #param input The input array of GPS structs
* #param output The output string which will contain lat, long
* #param sz Size left in the output buffer
* #return 0 Successfully completed operation
* 1 Failed / Error
*/
int get_gps60secString(GPS_periodic_t input[GPS_PERIODIC_ARRAY_SIZE],
char *output, size_t sz)
{
int cnt = snprintf(output, sz, "[");
if (cnt < 0 || cnt >= sz)
return 1;
output += cnt;
sz -= cnt;
int i = 0;
for (i = 0; i < GPS_PERIODIC_ARRAY_SIZE; i++) {
cnt = snprintf(output, sz, "[%0.8f,%0.8f]%s",
input[i].point.latitude, input[i].point.longitude,
i + 1 == GPS_PERIODIC_ARRAY_SIZE ? "" : ",");
if (cnt < 0 || cnt >= sz)
return 1;
output += cnt;
sz -= cnt;
}
cnt = snprintf(output, sz, "]");
if (cnt < 0 || cnt >= sz)
return 1;
return 0; // no error
}
/* #brief Create a GPS struct with data for testing. It will populate the
* point field of GPS_periodic_t. Lat starts from 0.0 and increases by 1*10^(-8)
* and Long will dstart at 99.99999999 and dec by 1*10^(-8)
*
* #param o_gps_60sec Output array of GPS structs
*/
void getLastMinGPSdata(GPS_periodic_t *o_gps_60sec)
{
//Fill in GPS related data here
int i = 0;
double latitude = o_gps_60sec[0].point.latitude;
double longitude = o_gps_60sec[0].point.longitude;
for (i = 0; i < 60; i++)
{
o_gps_60sec[i].point.latitude = latitude + (0.00000001 * (float)g_last +
0.00000001 * (float)i);
o_gps_60sec[i].point.longitude = longitude - (0.00000001 * (float)g_last +
0.00000001 * (float)i);
}
g_last = 60;
}
/* #brief Get the GPS data and convert it into a string
* #param trk Track structure with GPS string
*/
int getEvent_Track(Track_json_t *trk)
{
getLastMinGPSdata(l_gps_60Sec);
get_gps60secString(l_gps_60Sec, trk->Gnss60, GPS_STRING_SIZE);
return 0;
}
int main()
{
fptr = fopen("gpsAno.txt", "a");
if (fptr == NULL) {
printf("Error!!\n");
exit(1);
}
//Quit at signal interrupt
signal(SIGINT, userSignalInterrupt);
Track_json_t trk;
memset(&l_gps_60Sec, 0x00, sizeof(GPS_periodic_t) * GPS_PERIODIC_ARRAY_SIZE);
//Init Points to be zero and 99.99999999
int i = 0;
for (i = 0; i < 60; i++) {
l_gps_60Sec[i].point.latitude = 00.00000000;
l_gps_60Sec[i].point.longitude = 99.99999999;
}
do {
memset(&trk, 0, sizeof(Track_json_t));
getEvent_Track(&trk);
//Write to file
fprintf(fptr, "%s", trk.Gnss60);
fflush(fptr);
sleep(1);
} while (res == 0);
//close and exit
fclose(fptr);
return 0;
}
Note: Error was not recreated in the above code.
Because this doesn't have the strcat pitfalls.
I tested this function in the embedded application.
Through this I was able to find that the snprintf returns an error and the string created ended up to be:
[17.42401750,78.46098717],[17.42402083,53.62
It ended there (because of the return 1).
Does this mean that the data which was passed to snprints corrupted? It's a float value. How can it get corrupted?
Solution
The error have not been seen since I changed the sprintf function with one that doesn't directly deal with 64 bits of data.
Here's the function modp_dtoa2
/** \brief convert a floating point number to char buffer with a
* variable-precision format, and no trailing zeros
*
* This is similar to "%.[0-9]f" in the printf style, except it will
* NOT include trailing zeros after the decimal point. This type
* of format oddly does not exists with printf.
*
* If the input value is greater than 1<<31, then the output format
* will be switched exponential format.
*
* \param[in] value
* \param[out] buf The allocated output buffer. Should be 32 chars or more.
* \param[in] precision Number of digits to the right of the decimal point.
* Can only be 0-9.
*/
void modp_dtoa2(double value, char* str, int prec)
{
/* if input is larger than thres_max, revert to exponential */
const double thres_max = (double)(0x7FFFFFFF);
int count;
double diff = 0.0;
char* wstr = str;
int neg= 0;
int whole;
double tmp;
uint32_t frac;
/* Hacky test for NaN
* under -fast-math this won't work, but then you also won't
* have correct nan values anyways. The alternative is
* to link with libmath (bad) or hack IEEE double bits (bad)
*/
if (! (value == value)) {
str[0] = 'n'; str[1] = 'a'; str[2] = 'n'; str[3] = '\0';
return;
}
if (prec < 0) {
prec = 0;
} else if (prec > 9) {
/* precision of >= 10 can lead to overflow errors */
prec = 9;
}
/* we'll work in positive values and deal with the
negative sign issue later */
if (value < 0) {
neg = 1;
value = -value;
}
whole = (int) value;
tmp = (value - whole) * pow10[prec];
frac = (uint32_t)(tmp);
diff = tmp - frac;
if (diff > 0.5) {
++frac;
/* handle rollover, e.g. case 0.99 with prec 1 is 1.0 */
if (frac >= pow10[prec]) {
frac = 0;
++whole;
}
} else if (diff == 0.5 && ((frac == 0) || (frac & 1))) {
/* if halfway, round up if odd, OR
if last digit is 0. That last part is strange */
++frac;
}
/* for very large numbers switch back to native sprintf for exponentials.
anyone want to write code to replace this? */
/*
normal printf behavior is to print EVERY whole number digit
which can be 100s of characters overflowing your buffers == bad
*/
if (value > thres_max) {
sprintf(str, "%e", neg ? -value : value);
return;
}
if (prec == 0) {
diff = value - whole;
if (diff > 0.5) {
/* greater than 0.5, round up, e.g. 1.6 -> 2 */
++whole;
} else if (diff == 0.5 && (whole & 1)) {
/* exactly 0.5 and ODD, then round up */
/* 1.5 -> 2, but 2.5 -> 2 */
++whole;
}
//vvvvvvvvvvvvvvvvvvv Diff from modp_dto2
} else if (frac) {
count = prec;
// now do fractional part, as an unsigned number
// we know it is not 0 but we can have leading zeros, these
// should be removed
while (!(frac % 10)) {
--count;
frac /= 10;
}
//^^^^^^^^^^^^^^^^^^^ Diff from modp_dto2
// now do fractional part, as an unsigned number
do {
--count;
*wstr++ = (char)(48 + (frac % 10));
} while (frac /= 10);
// add extra 0s
while (count-- > 0) *wstr++ = '0';
// add decimal
*wstr++ = '.';
}
// do whole part
// Take care of sign
// Conversion. Number is reversed.
do *wstr++ = (char)(48 + (whole % 10)); while (whole /= 10);
if (neg) {
*wstr++ = '-';
}
*wstr='\0';
strreverse(str, wstr-1);
}
Here's (part of) my unabashedly opinionated guide on safe string handling in C. Normally, I would promote dynamic memory allocation instead of fixed-length strings, but in this case I'm assuming that in the embedded environment that might be problematic. (Although assumptions like that should always be checked.)
So, first things first:
Any function which creates a string in a buffer must be told explicitly how long the buffer is. This is non-negotiable.
As should be obvious, it's impossible for a function filling a buffer to check for buffer overflow unless it knows where the buffer ends. "Hope that the buffer is long enough" is not a viable strategy. "Document the needed buffer length" would be fine if everyone carefully read the documentation (they don't) and if the required length never changes (it will). The only thing that's left is an extra argument, which should be of type size_t (because that's the type of buffer lengths in the C library functions which require lengths).
Forget that strncpy and strncat exist. Also forget about strcat. They are not your friends.
strncpy is designed for a specific use case: ensuring that an entire fixed-length buffer is initialised. It is not designed for normal strings, and since it doesn't guarantee that the output is NUL-terminated, it doesn't produce a string.
If you're going to NUL-terminate yourself anyway, you might as well use memmove, or memcpy if you know that the source and destination don't overlap, which should almost always be the case. Since you'll want the memmove to stop at the end of the string for short strings (which strncpy does not do), measure the string length first with strnlen: strnlen takes a maximum length, which is precisely what you want in the case that you are going move a maximum number of characters.
Sample code:
/* Safely copy src to dst where dst has capacity dstlen. */
if (dstlen) {
/* Adjust to_move will have maximum value dstlen - 1 */
size_t to_move = strnlen(src, dstlen - 1);
/* copy the characters */
memmove(dst, src, to_move);
/* NUL-terminate the string */
dst[to_move] = 0;
}
strncat has a slightly more sensible semantic, but it's practically never useful because in order to use it, you already have to know how many bytes you could copy. In order to know that, in practice, you need to know how much space is left in your output buffer, and to know that you need to know where in the output buffer the copy will start. [Note 1]. But if you already know where the copy will start, what's the point of searching through the buffer from the beginning to find the copy point? And if you do let strncat do the search, how sure are you that your previously computed start point is correct?
In the above code snippet, we already computed the length of the copy. We can extend that to do an append without rescanning:
/* Safely copy src1 and then src2 to dst where dst has capacity dstlen. */
/* Assumes that src1 and src2 are not contained in dst. */
if (dstlen) {
/* Adjust to_move will have maximum value dstlen - 1 */
size_t to_move = strnlen(src1, dstlen - 1);
/* Copy the characters from src1 */
memcpy(dst, src1, to_move);
/* Adjust the output pointer and length */
dst += to_move;
dstlen -= to_move;
/* Now safely copy src2 to just after src1. */
to_move = strnlen(src2, dstlen - 1);
memcpy(dst, src2, to_move);
/* NUL-terminate the string */
dst[to_move] = 0;
}
It might be that we want the original values of dst and dstlen after creating the string, and it might also be that we want to know how many bytes we inserted into dst in all. In that case, we would probably want to make copies of those variables before doing the copies, and save the cumulative sum of moves.
The above assumes that we're starting with an empty output buffer, but perhaps that isn't the case. Since we still need to know where the copy will start in order to know how many characters we can put at the end, we can still use memcpy; we just need to scan the output buffer first to find the copy point. (Only do this if there is no alternative. Doing it in a loop instead of recording the next copy point is Shlemiel the Painter's algorithm.)
/* Safely append src to dst where dst has capacity dstlen and starts
* with a string of unknown length.
*/
if (dstlen) {
/* The following code will "work" even if the existing string
* is not correctly NUL-terminated; the code will not copy anything
* from src, but it will put a NUL terminator at the end of the
* output buffer.
*/
/* Figure out where the existing string ends. */
size_t prefixlen = strnlen(dst, dstlen - 1);
/* Update dst and dstlen */
dst += prefixlen;
dstlen -= prefixlen;
/* Proceed with the append, as above. */
size_t to_move = strnlen(src, dstlen - 1);
memmove(dst, src, to_move);
dst[to_move] = 0;
}
Embrace snprintf. It really is your friend. But always check its return value.
Using memmove, as above, is slightly awkward. It requires you to manually check that the buffer's length is not zero (otherwise subtracting one would be disastrous since the length is unsigned), and it requires you to manually NUL-terminate the output buffer, which is easy to forget and the source of many bugs. It is very efficient, but sometimes it's worth sacrificing a little efficiency so that your code is easier to write and easier to read and verify.
And that leads us directly to snprintf. For example, you can replace:
if (dstlen) {
size_t to_move = strnlen(src, dstlen - 1);
memcpy(dst, src, to_move);
dst[to_move] = 0;
}
with the much simpler
int copylen = snprintf(dst, dstlen, "%s", src);
That does everything: checks that dstlen is not 0; only copies the characters from src which can fit in dst, and correctly NUL-terminates dst (unless dstlen was 0). And the cost is minimal; it takes very little time to parse the format string "%s" and most implementations are pretty well optimised for this case. [Note 2]
But snprintf is not a panacea. There are still a couple of really important warnings.
First, the documentation for snprintf makes clear that it is not permitted for any input argument to overlap the output range. (So it replaces memcpy but not memmove.) Remember that overlap includes NUL-terminators, so the following code which attempts to double the string in str instead leads to Undefined Behaviour:
char str[BUFLEN];
/* Put something into str */
get_some_data(str, BUFLEN);
/* DO NOT DO THIS: input overlaps output */
int result = snprintf(str, BUFLEN, "%s%s", str, str);
/* DO NOT DO THIS EITHER; IT IS STILL UB */
size_t len = strnlen(str, cap - 1);
int result = snprintf(str + len, cap - len, "%s", str);
The problem with the second invocation of snprintf is that the NUL which terminates str is precisely at str + len, the first byte of the output buffer. That's an overlap, so it's illegal.
The second important note about snprintf is that it returns a value, which must not be ignored. The value returned is not the length of the string created by snprintf. It's the length the string would have been had it not been truncated to fit in the output buffer.
If no truncation occurred, then the result is the length of the result, which must be strictly less than the size of the output buffer (because there must be room for a NUL terminator, which is not considered part of the length of the result.) You can use this fact to check whether truncation occurred:
if (result >= dstlen) /* Output was truncated */
This can be used, for example, to redo the snprintf with a larger, dynamically-allocated buffer (of size result + 1; never forget the need to NUL-terminate).
But remember that the result is an int -- that is, a signed value. That means that snprintf cannot cope with very long strings. That's not likely to be an issue in embedded code, but on systems where it's conceivable that strings exceed 2GB, you may not be able to safely use %s formats in snprintf. It also means that snprintf is allowed to return a negative value to indicate an error. Very old implementations of snprintf returned -1 to indicate truncation, or in response to being called with buffer length 0. That's not standard behaviour according to C99 (nor recent versions of Posix), but you should be prepared for it.
Standard-compliant implementations of snprintf will return a negative value if the buffer length argument is too big to fit in a (signed) int; it's not clear to me what the expected return value is if the buffer length is OK but the untruncated length is too big for an int. A negative value will also be returned if you used a conversion which resulted in an encoding error; for example, a %lc conversion whose corresponding argument contains an integer which cannot be converted to a multibyte (typically UTF-8) sequence.
In short, you should always check the return value of snprintf (recent gcc/glibc versions will produce a warning if you do not), and you should be prepared for it to be negative.
So, with all that behind us, let's write a function which produces a string of co-ordinate pairs:
/* Arguments:
* buf the output buffer.
* buflen the capacity of buf (including room for trailing NUL).
* points a vector of struct Point pairs.
* npoints the number of objects in points.
* Description:
* buf is overwritten with a comma-separated list of points enclosed in
* square brackets. Each point is output as a comma-separated pair of
* decimal floating point numbers enclosed in square brackets. No more
* than buflen - 1 characters are written. Unless buflen is 0, a NUL is
* written following the (possibly-truncated) output.
* Return value:
* If the output buffer contains the full output, the number of characters
* written to the output buffer, not including the NUL terminator.
* If the output was truncated, (size_t)(-1) is returned.
*/
size_t sprint_points(char* buf, size_t buflen,
struct Point const* points, size_t npoints)
{
if (buflen == 0) return (size_t)(-1);
size_t avail = buflen;
char delim = '['
while (npoints) {
int res = snprintf(buf, avail, "%c[%f,%f]",
delim, points->lat, points->lon);
if (res < 0 || res >= avail) return (size_t)(-1);
buf += res; avail -= res;
++points; --npoints;
delim = ',';
}
if (avail <= 1) return (size_t)(-1);
strcpy(buf, "]");
return buflen - (avail - 1);
}
Notes
You will often see code like this:
strncat(dst, src, sizeof(src)); /* NEVER EVER DO THIS! */
Telling strncat not to append more characters from src than can fit in src is obviously pointless (unless src is not correctly NUL-terminated, in which case you have a bigger problem). More importantly, it does absolutely nothing to protect you from writing beyond the end of the output buffer, since you have not done anything to check that dst has room for all those characters. So about all it does is get rid of compiler warnings about the unsafety of strcat. Since this code is exactly as unsafe as strcat was, you probably would be better off with the warning.
You might even find a compiler which understands snprintf will enough to parse the format string at compile time, so the convenience comes at no cost at all. (And if your current compiler doesn't do this, no doubt a future version will.) As with any use of the *printf family, you should never try to economize keystrokes by
leaving out the format string (snprintf(dst, dstlen, src) instead of snprintf(dst, dstlen, "%s", src).) That's unsafe (it has undefined behaviour if src contains an unduplicated %). And it's much slower because the library function has to parse the entire string to be copied looking for percent signs, instead of just copying it to the output.
Code is using functions that expect pointers to string, yet not always passing pointers to strings as arguments.
Stray characters seen at output of snprintf
A string must have a terminating null character.
strncat(char *, .... expects the first parameter to be a pointer to a string. memcpy(output, "[",1); does not insure that. #Jeremy
memcpy(output, "[",1);
...
strncat(output, temp,sizeof(temp));
This is a candidate source of stray characters.
strncat(...., ..., size_t size). itself is a problem as the size is the amount of space available for concatenating (minus the null character). The size available to char * output is not passed in. #Jonathan Leffler. Might as well do strcat() here.
Instead, pass in the size available to output to prevent buffer overflow.
#define N 60
int get_gps60secString(GPS_periodic_t input[N], char *output, size_t sz) {
int cnt = snprintf(output, sz, "[");
if (cnt < 0 || cnt >= sz)
return 1;
output += cnt;
sz -= cnt;
int i = 0;
for (i = 0; i < N; i++) {
cnt = snprintf(output, size, "[%0.8f,%0.8f]%s", input[i].point.latitude,
input[i].point.longitude, i + 1 == N ? "" : ",");
if (cnt < 0 || cnt >= sz)
return 1;
output += cnt;
sz -= cnt;
}
cnt = snprintf(output, sz, "]");
if (cnt < 0 || cnt >= sz)
return 1;
return 0; // no error
}
OP has posted more code - will review.
Apparently the buffer char *output is pre-filled with 0 before the get_gps60secString() so the missing null character from memcpy(output, "[",1); should not cause the issue - hmmmmmm
unsigned short SendTrack() does not return a value. 1) Using its result value is UB. 2) Enable all compiler warnings.

Building a PHP Extension using original rijndael, correct encryption/decrypt however trailing extra bytes

So I have just begun writing a PHP Extension, using the original Rijndael code (which is now formally AES).
However it seems there is a bug somewhere in the code, I know it encrypts/decrypts correctly, but on the output it adds a extra 6 bytes to the string, which I assume is something to do with the conversion from uint8_t array to char array.
I havent posted the code here as it would take up half the page, so I have posted it to github here :
https://github.com/Hect0rius/PHPEXT-Rijndael
The main code I am referring to is the following is in php_rijndael.c (2 functions:
/* {{{ proto resource rijndael_encrypt(string inData, string key)
encrypts a string with rijndael /
PHP_FUNCTION(rijndael_encrypt)
{
/ Inputs */
char *inData; // Data Ptr.
size_t inDataLen; // Data Length.
char *key; // Key Ptr.
size_t keyLen; // Key Length.
zend_ulong keyBits; // Bits, between 128/192/256.
/* Get Parameters from Zend */
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s|l", &inData, &inDataLen, &key, &keyLen, &keyBits) == FAILURE) {
return;
}
/* Since rijndael takes what it needs via key bits, then we just allow the overflow of the key. */
switch(keyBits) {
case 128:
if(keyLen < 16) { php_error_docref(NULL, E_WARNING, "Key length must be 16 characters long."); RETURN_FALSE; }
break;
case 192:
if(keyLen < 24) { php_error_docref(NULL, E_WARNING, "Key length must be 24 characters long."); RETURN_FALSE; }
break;
case 256:
if(keyLen < 32) { php_error_docref(NULL, E_WARNING, "Key length must be 32 characters long."); RETURN_FALSE; }
break;
}
/* Convert from original pointers to uin8_t arrays */
uint8_t dataU8[16];
uint8_t keyU8[16];
uint8_t output[16], i = 0;
do {
dataU8[i] = (uint8_t)inData[i];
keyU8[i] = (uint8_t)key[i];
i++;
}
while(i < 16);
/* Setup Rijndael stack */
uint32_t rk[4 * (MAXNR + 1)];
int32_t Nr = rijndaelKeySetupEnc(rk, keyU8, keyBits);
/* Decrypt Buffer. */
rijndaelEncrypt(rk, Nr, dataU8, output);
/* Now return data back into a char array*/
char outChar[16], *ptr = outChar;
i = 0;
do {
ptr[i] = (char)output[i];
i++;
}
while(i < 16);
RETURN_STRING(outChar);
}
/* }}} */
/* {{{ proto resource rijndael_decrypt(string inData, string key)
decrypts a string with rijndael /
PHP_FUNCTION(rijndael_decrypt)
{
/ Inputs */
char *inData; // Data Ptr.
size_t inDataLen; // Data Length.
char *key; // Key Ptr.
size_t keyLen; // Key Length.
zend_ulong keyBits; // Bits, between 128/192/256.
/* Get Parameters from Zend */
if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|s|l", &inData, &inDataLen, &key, &keyLen, &keyBits) == FAILURE) {
return;
}
/* Since rijndael takes what it needs via key bits, then we just allow the overflow of the key. */
switch(keyBits) {
case 128:
if(keyLen < 16) { php_error_docref(NULL, E_WARNING, "Key length must be 16 characters long."); RETURN_FALSE; }
break;
case 192:
if(keyLen < 24) { php_error_docref(NULL, E_WARNING, "Key length must be 24 characters long."); RETURN_FALSE; }
break;
case 256:
if(keyLen < 32) { php_error_docref(NULL, E_WARNING, "Key length must be 32 characters long."); RETURN_FALSE; }
break;
}
/* Convert from original pointers to uin8_t arrays */
uint8_t dataU8[16];
uint8_t keyU8[16];
uint8_t output[16], i = 0;
do {
dataU8[i] = (uint8_t)inData[i];
keyU8[i] = (uint8_t)key[i];
i++;
}
while(i < 16);
/* Setup Rijndael Stack */
uint32_t rk[4 * (MAXNR + 1)];
int32_t Nr = rijndaelKeySetupDec(rk, keyU8, keyBits);
/* Decrypt input uint8_t array */
rijndaelDecrypt(rk, Nr, dataU8, output);
/* Convert data back to a char */
char outChar[16], *ptr = outChar;
i = 0;
do {
ptr[i] = (char)output[i];
i++;
}
while(i < 16);
RETURN_STRING(ptr);
}
/* }}} */
#endif /* HAVE_RIJNDAEL */
I only guess it is correctly decrypting the encrypted buffer as it outputs back to all zero's, here is the test.php file:
You are seeing padding.
AES (and Rijndael) are block ciphers and as such process data in blocks, 16-bytes for AES.
If the input is not an exact multiple of the block size some padding needs to be added to the data to be encrypted and removed on decryption. The most common padding is PKCS#7 however some implementations are brain-dead and do not support PKCS#7, sometimes using null padding which can not support encrypting binary data.
Note: The PHP mcrypt implementation does not support standard PKCS#7 (née PKCS#5) padding, only non-standard null padding that can't even be used with binary data.

Resources