Skip to content

Instantly share code, notes, and snippets.

@charlesnicholson
Created December 28, 2023 22:11
Show Gist options
  • Save charlesnicholson/b895097b09e8a83df4a349e98b0ceb49 to your computer and use it in GitHub Desktop.
Save charlesnicholson/b895097b09e8a83df4a349e98b0ceb49 to your computer and use it in GitHub Desktop.
Demonstrate bugs in Wikipedia's cobsDecode C sample
#include <assert.h>
#include <stddef.h>
#include <stdint.h>
#include <stdio.h>
#define USE_WIKIPEDIA_COBS_DECODE 1
#if USE_WIKIPEDIA_COBS_DECODE
size_t cobsDecode(const uint8_t *buffer, size_t length, void *data) {
assert(buffer && data);
const uint8_t *byte = buffer; // Encoded input byte pointer
uint8_t *decode = (uint8_t *)data; // Decoded output byte pointer
for (uint8_t code = 0xff, block = 0; byte < buffer + length; --block) {
if (block) // Decode block byte
*decode++ = *byte++;
else {
if (code != 0xff) // Encoded zero, write it
*decode++ = 0;
block = code = *byte++; // Next block length
if (!code) // Delimiter code found
break;
}
}
return (size_t)(decode - (uint8_t *)data);
}
#else
size_t cobsDecode(const uint8_t *buffer, size_t length, void *data) {
assert(buffer && data);
const uint8_t *byte = buffer; // Encoded input byte pointer
uint8_t *decode = (uint8_t *)data; // Decoded output byte pointer
for (uint8_t code = 0xff, block = 0; byte < buffer + length; --block) {
if (block) // Decode block byte
*decode++ = *byte++;
else {
block = *byte++; // Fetch the next block length
if (block && (code != 0xff)) // Encoded zero, write it unless it's final.
*decode++ = 0;
code = block;
if (!code) // Delimiter code found
break;
}
}
return (size_t)(decode - (uint8_t *)data);
}
#endif
unsigned char s_decoded[1024];
void wikipedia_example(unsigned index, unsigned char const *encoded,
size_t encoded_len, unsigned char const *expected,
unsigned expected_len) {
size_t const len = cobsDecode(encoded, encoded_len, s_decoded);
printf("Example %u: Expected (%u)", index, expected_len);
for (size_t i = 0; i < expected_len; ++i) {
printf(" 0x%02X", expected[i]);
}
printf(", Actual (%u)", (unsigned)len);
for (size_t i = 0; i < len; ++i) {
printf(" 0x%02X", s_decoded[i]);
}
printf("\n");
}
void wikipedia_example_1(void) {
unsigned char const encoded[] = {0x01, 0x01, 0x00};
unsigned char const expected[] = {0x00};
wikipedia_example(1, encoded, sizeof(encoded), expected, sizeof(expected));
}
void wikipedia_example_2(void) {
unsigned char const encoded[] = {0x01, 0x01, 0x00, 0x00};
unsigned char const expected[] = {0x00, 0x00};
wikipedia_example(2, encoded, sizeof(encoded), expected, sizeof(expected));
}
void wikipedia_example_3(void) {
unsigned char const encoded[] = {0x01, 0x02, 0x11, 0x01, 0x00};
unsigned char const expected[] = {0x00, 0x11, 0x00};
wikipedia_example(3, encoded, sizeof(encoded), expected, sizeof(expected));
}
void wikipedia_example_4(void) {
unsigned char const encoded[] = {0x03, 0x11, 0x22, 0x02, 0x33, 0x00};
unsigned char const expected[] = {0x11, 0x22, 0x00, 0x33};
wikipedia_example(4, encoded, sizeof(encoded), expected, sizeof(expected));
}
void wikipedia_example_5(void) {
unsigned char const encoded[] = {0x05, 0x11, 0x22, 0x33, 0x44, 0x00};
unsigned char const expected[] = {0x11, 0x22, 0x33, 0x44};
wikipedia_example(5, encoded, sizeof(encoded), expected, sizeof(expected));
}
void wikipedia_example_6(void) {
unsigned char const encoded[] = {0x02, 0x11, 0x01, 0x01, 0x01, 0x00};
unsigned char const expected[] = {0x11, 0x00, 0x00, 0x00};
wikipedia_example(6, encoded, sizeof(encoded), expected, sizeof(expected));
}
int main(int argc, char const *argv[]) {
(void)argc;
(void)argv;
wikipedia_example_1();
wikipedia_example_2();
wikipedia_example_3();
wikipedia_example_4();
wikipedia_example_5();
wikipedia_example_6();
return 0;
}
@charlesnicholson
Copy link
Author

Hi Wikipedia folks- I don't have an account over there but am happy to discuss over here if that's interesting / helpful. I hope this example displays the bug well enough.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment