Commit 5312cb01 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Move the checksum to the beginning of the pyc

Now more resilient to truncated pyc files; got into a bad situation
where the parser crashed, wrote out a half-pyc file, which wasn't
judged to be invalid.
parent d2cbb9aa
...@@ -869,7 +869,7 @@ AST_Module* parse(const char* fn) { ...@@ -869,7 +869,7 @@ AST_Module* parse(const char* fn) {
#define MAGIC_STRING "a\nch" #define MAGIC_STRING "a\nch"
#define MAGIC_STRING_LENGTH 4 #define MAGIC_STRING_LENGTH 4
#define LENGTH_SUFFIX_LENGTH 4 #define CHECKSUM_LENGTH 4
static void _reparse(const char* fn, const std::string& cache_fn) { static void _reparse(const char* fn, const std::string& cache_fn) {
FILE* parser = popen(getParserCommandLine(fn).c_str(), "r"); FILE* parser = popen(getParserCommandLine(fn).c_str(), "r");
...@@ -878,7 +878,14 @@ static void _reparse(const char* fn, const std::string& cache_fn) { ...@@ -878,7 +878,14 @@ static void _reparse(const char* fn, const std::string& cache_fn) {
fwrite(MAGIC_STRING, 1, MAGIC_STRING_LENGTH, cache_fp); fwrite(MAGIC_STRING, 1, MAGIC_STRING_LENGTH, cache_fp);
int bytes_written = 0; int checksum_start = ftell(cache_fp);
int bytes_written = -1;
// Currently just use the length as the checksum
static_assert(sizeof(bytes_written) >= CHECKSUM_LENGTH, "");
fwrite(&bytes_written, 1, CHECKSUM_LENGTH, cache_fp);
bytes_written = 0;
char buf[80]; char buf[80];
while (true) { while (true) {
int nread = fread(buf, 1, 80, parser); int nread = fread(buf, 1, 80, parser);
...@@ -888,10 +895,8 @@ static void _reparse(const char* fn, const std::string& cache_fn) { ...@@ -888,10 +895,8 @@ static void _reparse(const char* fn, const std::string& cache_fn) {
fwrite(buf, 1, nread, cache_fp); fwrite(buf, 1, nread, cache_fp);
} }
// Ideally this should be a full checksum rather than just a length. fseek(cache_fp, checksum_start, SEEK_SET);
// And maybe it should be put at the beginning? fwrite(&bytes_written, 1, CHECKSUM_LENGTH, cache_fp);
static_assert(sizeof(bytes_written) >= LENGTH_SUFFIX_LENGTH, "");
fwrite(&bytes_written, 1, LENGTH_SUFFIX_LENGTH, cache_fp);
int code = pclose(parser); int code = pclose(parser);
assert(code == 0); assert(code == 0);
...@@ -928,20 +933,25 @@ AST_Module* caching_parse(const char* fn) { ...@@ -928,20 +933,25 @@ AST_Module* caching_parse(const char* fn) {
char buf[MAGIC_STRING_LENGTH]; char buf[MAGIC_STRING_LENGTH];
int read = fread(buf, 1, MAGIC_STRING_LENGTH, fp); int read = fread(buf, 1, MAGIC_STRING_LENGTH, fp);
if (read != MAGIC_STRING_LENGTH || strncmp(buf, MAGIC_STRING, MAGIC_STRING_LENGTH) != 0) { if (read != MAGIC_STRING_LENGTH || strncmp(buf, MAGIC_STRING, MAGIC_STRING_LENGTH) != 0) {
if (VERBOSITY()) {
printf("Warning: corrupt or non-Pyston .pyc file found; ignoring\n");
}
good = false; good = false;
} }
} }
if (good) { if (good) {
int length = 0; int length = 0;
fseek(fp, -LENGTH_SUFFIX_LENGTH, SEEK_END);
static_assert(sizeof(length) >= LENGTH_SUFFIX_LENGTH, "");
int read = fread(&length, 1, LENGTH_SUFFIX_LENGTH, fp);
fseek(fp, MAGIC_STRING_LENGTH, SEEK_SET); fseek(fp, MAGIC_STRING_LENGTH, SEEK_SET);
static_assert(sizeof(length) >= CHECKSUM_LENGTH, "");
int read = fread(&length, 1, CHECKSUM_LENGTH, fp);
int expected_length = MAGIC_STRING_LENGTH + LENGTH_SUFFIX_LENGTH + length; int expected_total_length = MAGIC_STRING_LENGTH + CHECKSUM_LENGTH + length;
if (read != LENGTH_SUFFIX_LENGTH || expected_length != cache_stat.st_size) { if (read != CHECKSUM_LENGTH || expected_total_length != cache_stat.st_size) {
if (VERBOSITY()) {
printf("Warning: truncated .pyc file found; ignoring\n");
}
good = false; good = false;
} }
} }
...@@ -962,7 +972,7 @@ AST_Module* caching_parse(const char* fn) { ...@@ -962,7 +972,7 @@ AST_Module* caching_parse(const char* fn) {
BufferedReader* reader = new BufferedReader(fp); BufferedReader* reader = new BufferedReader(fp);
AST* rtn = readASTMisc(reader); AST* rtn = readASTMisc(reader);
reader->fill(); reader->fill();
assert(reader->bytesBuffered() == LENGTH_SUFFIX_LENGTH); assert(reader->bytesBuffered() == 0);
delete reader; delete reader;
assert(rtn->type == AST_TYPE::Module); assert(rtn->type == AST_TYPE::Module);
......
# expected: fail
# - currently throws an AttributeError if we imported the module but the name didn't exist
try:
import non_existent_module
assert 0, "shouldn't get here"
except ImportError:
pass
try:
from non_existent_module import a
assert 0, "shouldn't get here"
except ImportError:
pass
try:
from sys import non_existent_attribute
assert 0, "shouldn't get here"
except ImportError:
pass
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment