Code Generation Issue
Code Generation Issue
- Subject: Code Generation Issue
- From: Andreas Grosam <email@hidden>
- Date: Tue, 15 Nov 2011 17:39:49 +0100
Hello All,
I'm experiencing a strange runtime bug in my code that occurs only if compiled with Apple LLVM compiler 3.0 and optimization flag O2 or higher on Mac OS X. Code compiled with LLVM GCC 4.2 does not have this issue. As far as I can see, the logic is correct.
I usually hesitate to blame the compiler, but I can't see were I possibly made an error in the source here.
Below is the functions where the issue occurs (note: complete source is below):
The problem is in the while loop. It appears, the emitted code for incrementing the pointer "first" is not correct. What happens is, the pointer 'first' will be incremented beyond pointer 'last'. If the code were correct, first shall point to pointer 'last' when the loop exits. The result is incorrect logic. There is a test case below which shows this.
If I put a 'break' statement as shown in lines 24 and 29, the compiler generated code works correct.
These 'break' statements are strictly not required for a correct logic, but if set, it forces the loop to exit at the correct point - which otherwise does not happen.
It seems important to note, that the pointer 'first' will not only be incremented once, but several times within the while loop, albeit it will be checked.
The statement 'continue' at line 20 may be optional. When set, it has no effect on the correctness of the code.
1: char* encodeBase64(const char* first,const char* last, char* result)
2: {
3: const char base64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4:
5: int padding = 0;
6: uint32_t n;
7: while (first != last)
8: {
9: // Read the next three bytes (if available) into one 24-bit number:
10: n = to_int(*first) << 16;
11: ++first;
12: if (first != last) {
13: n |= (to_int(*first) << 8);
14: ++first;
15: if (first != last) {
16: n |= to_int(*first);
17: ++first;
18: // encode 'n' into 4 bytes:
19: …
20: //continue;
21: }
22: else {
23: padding = 1;
24: //break; // <==
25: }
26: }
27: else {
28: padding = 2;
29: //break; // <==
30: }
31: }
32:
33: // Count for padding:
34: switch (padding) {
35: ...
36: }
37:
38: return result;
39: }
Full source:
===========================================================
//
// main.cpp
// base64
//
#include <iostream>
#include <iterator>
#include <unistd.h>
namespace base64 {
namespace detail {
template <typename T>
int to_int(const T& v) {
return static_cast<int>(static_cast<uint8_t>(v));
}
}
template <class InputIterator, class OutputIterator>
OutputIterator encodeBase64(InputIterator first, InputIterator last, OutputIterator result)
{
using detail::to_int;
const char base64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int padding = 0;
uint32_t n;
while (first != last)
{
// Read the next three bytes (if available) into one 24-bit number:
n = to_int(*first) << 16;
++first;
if (first != last) {
n |= (to_int(*first) << 8);
++first;
if (first != last) {
n |= to_int(*first);
++first;
// encode it into 4 bytes:
*result++ = base64chars[static_cast<uint8_t>(n >> 18) & 0x3Fu];
*result++ = base64chars[static_cast<uint8_t>(n >> 12) & 0x3Fu];
*result++ = base64chars[static_cast<uint8_t>(n >> 6) & 0x3Fu];
*result++ = base64chars[static_cast<uint8_t>(n) & 0x3Fu];
//continue;
}
else {
padding = 1;
//break; // <==
}
}
else {
padding = 2;
//break; // <==
}
}
// Count for padding:
switch (padding) {
case 1:
*result++ = base64chars[static_cast<uint8_t>(n >> 18) & 0x3Fu];
*result++ = base64chars[static_cast<uint8_t>(n >> 12) & 0x3Fu];
*result++ = base64chars[static_cast<uint8_t>(n >> 6) & 0x3Fu];
*result++ = '=';
break;
case 2:
*result++ = base64chars[static_cast<uint8_t>(n >> 18) & 0x3Fu];
*result++ = base64chars[static_cast<uint8_t>(n >> 12) & 0x3Fu];
*result++ = '=';
*result++ = '=';
break;
default:;
}
return result;
}
}
namespace {
std::string
encode(const std::string& in)
{
std::string result;
base64::encodeBase64(in.begin(), in.end(), std::back_inserter(result));
return result;
}
}
int main (int argc, const char * argv[])
{
try {
struct test_s {
const char* a_;
const char* b_;
};
test_s tests[] = {
"", "",
"f", "Zg==",
"fo", "Zm8=",
"foo", "Zm9v",
"foob", "Zm9vYg==",
"fooba", "Zm9vYmE=",
"foobar", "Zm9vYmFy"
};
int count = sizeof(tests)/sizeof(test_s);
for (int i = 0; i < count; ++i) {
std::string a = tests[i].a_;
std::string b = tests[i].b_;
std::cout << "encoding: \"" << a << "\"" << std::endl;
std::string encode_test = encode(a);
if (b != encode_test) {
std::cout << "Error encode: in: '" << a << "', out: '" << b << "'" << ", result: '" << encode_test << "'" << std::endl;
}
}
}
catch (std::exception& ex) {
std::cout << "Error: " << ex.what() << std::endl;
return -1;
}
return 0;
}
// Output when compiled with clang, optimization O2 (or higher):
encoding: ""
encoding: "f"
encoding: "fo"
encoding: "foo"
encoding: "foob"
Error encode: in: 'foob', out: 'Zm9vYg==', result: 'Zm9vb29ib2=='
encoding: "fooba"
encoding: "foobar"
Regards
Andreas
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Xcode-users mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden