Skip to content

Commit

Permalink
Fix version with NULLPTR in JSON output
Browse files Browse the repository at this point in the history
global._version has been changed at some point to an
null-terminated string. However, its type was still a D string. Some
parts of the code base were updated to do `.length - 1`, but other like
the `compilerInfo` were forgotten. This change remedies this and:
- removes null terminator from the D string of _version
- initializes versionNumber at compile-time
- expose _version as versionString
  • Loading branch information
wilzbach committed Aug 28, 2020
1 parent 6036ef2 commit 2fc0968
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 42 deletions.
2 changes: 1 addition & 1 deletion src/dmd/backend/dwarfdbginf.d
Original file line number Diff line number Diff line change
Expand Up @@ -1126,7 +1126,7 @@ static if (ELFOBJ || MACHOBJ)
version (MARS)
{
debug_info.buf.write("Digital Mars D ");
debug_info.buf.write(config._version); // DW_AT_producer
debug_info.buf.writeString(config._version); // DW_AT_producer
// DW_AT_language
debug_info.buf.writeByte((config.fulltypes == CVDWARF_D) ? DW_LANG_D : DW_LANG_C89);
}
Expand Down
5 changes: 3 additions & 2 deletions src/dmd/backend/elfobj.d
Original file line number Diff line number Diff line change
Expand Up @@ -1500,10 +1500,11 @@ void Obj_compiler()
enum n = compilerHeader.length;
char[n + maxVersionLength] compiler = compilerHeader;

assert(config._version.length < maxVersionLength);
assert(config._version.length + 1 < maxVersionLength);
const newLength = n + config._version.length;
compiler[n .. newLength] = config._version;
comment_data.write(compiler[0 .. newLength]);
compiler[newLength] = 0;
comment_data.write(compiler[0 .. newLength + 1]);
//dbg_printf("Comment data size %d\n",comment_data.length());
}

Expand Down
2 changes: 1 addition & 1 deletion src/dmd/dmsc.d
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ void backend_init()
params.useModuleInfo && Module.moduleinfo,
params.useTypeInfo && Type.dtypeinfo,
params.useExceptions && ClassDeclaration.throwable,
global._version
global.versionString()
);

debug
Expand Down
75 changes: 42 additions & 33 deletions src/dmd/globals.d
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,8 @@ extern (C++) struct Global
Array!(const(char)*)* path; // Array of char*'s which form the import lookup path
Array!(const(char)*)* filePath; // Array of char*'s which form the file import lookup path

string _version;
private enum string _version = import("VERSION");
private enum uint _versionNumber = parseVersionNumber(_version);
const(char)[] vendor; // Compiler backend name

Param params;
Expand Down Expand Up @@ -371,8 +372,6 @@ extern (C++) struct Global

extern (C++) void _init()
{
_version = import("VERSION") ~ '\0';

version (MARS)
{
vendor = "Digital Mars D";
Expand Down Expand Up @@ -460,41 +459,51 @@ extern (C++) struct Global
}

/**
Returns: the version as the number that would be returned for __VERSION__
*/
extern(C++) uint versionNumber()
* Computes the version number __VERSION__ from the compiler version string.
*/
extern (D) private static uint parseVersionNumber(string version_)
{
import core.stdc.ctype;
__gshared uint cached = 0;
if (cached == 0)
//
// parse _version
//
uint major = 0;
uint minor = 0;
bool point = false;
// skip initial 'v'
foreach (const c; version_[1..$])
{
//
// parse _version
//
uint major = 0;
uint minor = 0;
bool point = false;
for (const(char)* p = _version.ptr + 1;; p++)
if ('0' <= c && c <= '9') // isdigit
{
const c = *p;
if (isdigit(cast(char)c))
{
minor = minor * 10 + c - '0';
}
else if (c == '.')
{
if (point)
break; // ignore everything after second '.'
point = true;
major = minor;
minor = 0;
}
else
break;
minor = minor * 10 + c - '0';
}
cached = major * 1000 + minor;
else if (c == '.')
{
if (point)
break; // ignore everything after second '.'
point = true;
major = minor;
minor = 0;
}
else
break;
}
return cached;
return major * 1000 + minor;
}

/**
Returns: the version as the number that would be returned for __VERSION__
*/
extern(C++) uint versionNumber()
{
return _versionNumber;
}

/**
Returns: compiler version string.
*/
extern(C++) string versionString()
{
return _version;
}

/**
Expand Down
6 changes: 5 additions & 1 deletion src/dmd/globals.h
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,6 @@ struct Global
Array<const char *> *path; // Array of char*'s which form the import lookup path
Array<const char *> *filePath; // Array of char*'s which form the file import lookup path

DString version; // Compiler version string
DString vendor; // Compiler backend name

Param params;
Expand Down Expand Up @@ -317,6 +316,11 @@ struct Global
Returns: the version as the number that would be returned for __VERSION__
*/
unsigned versionNumber();

/**
Returns: the compiler version string.
*/
DString versionString();
};

extern Global global;
Expand Down
2 changes: 1 addition & 1 deletion src/dmd/json.d
Original file line number Diff line number Diff line change
Expand Up @@ -829,7 +829,7 @@ public:
{
objectStart();
requiredProperty("vendor", global.vendor);
requiredProperty("version", global._version);
requiredProperty("version", global.versionString());
property("__VERSION__", global.versionNumber());
requiredProperty("interface", determineCompilerInterface());
property("size_t", size_t.sizeof);
Expand Down
6 changes: 3 additions & 3 deletions src/dmd/mars.d
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ private void logo()
{
printf("DMD%llu D Compiler %.*s\n%.*s %.*s\n",
cast(ulong)size_t.sizeof * 8,
cast(int) global._version.length - 1, global._version.ptr,
cast(int) global.versionString().length, global.versionString().ptr,
cast(int)global.copyright.length, global.copyright.ptr,
cast(int)global.written.length, global.written.ptr
);
Expand All @@ -93,7 +93,7 @@ extern(C) void printInternalFailure(FILE* stream)
"with, preferably, a reduced, reproducible example and the information below.\n" ~
"DustMite (https://github.com/CyberShadow/DustMite/wiki) can help with the reduction.\n" ~
"---\n").ptr, stream);
stream.fprintf("DMD %.*s\n", cast(int) global._version.length - 1, global._version.ptr);
stream.fprintf("DMD %.*s\n", cast(int) global.versionString().length, global.versionString().ptr);
stream.printPredefinedVersions;
stream.printGlobalConfigs();
fputs("---\n".ptr, stream);
Expand Down Expand Up @@ -1310,7 +1310,7 @@ private void printPredefinedVersions(FILE* stream)
extern(C) void printGlobalConfigs(FILE* stream)
{
stream.fprintf("binary %.*s\n", cast(int)global.params.argv0.length, global.params.argv0.ptr);
stream.fprintf("version %.*s\n", cast(int) global._version.length - 1, global._version.ptr);
stream.fprintf("version %.*s\n", cast(int) global.versionString().length, global.versionString().ptr);
const iniOutput = global.inifilename ? global.inifilename : "(none)";
stream.fprintf("config %.*s\n", cast(int)iniOutput.length, iniOutput.ptr);
// Print DFLAGS environment variable
Expand Down
9 changes: 9 additions & 0 deletions src/tests/cxxfrontend.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,14 @@ void test_tokens()
assert(strcmp(Token::toChars(TOKvectorarray), "vectorarray") == 0);
}

void test_compiler_globals()
{
// only check constant prefix of version
assert(strncmp(global.versionString().ptr, "v2.", 3) == 0);
unsigned versionNumber = global.versionNumber();
assert(versionNumber >= 2060 && versionNumber <= 3000);
}

/**********************************/

class TestVisitor : public Visitor
Expand Down Expand Up @@ -457,6 +465,7 @@ int main(int argc, char **argv)
frontend_init();

test_tokens();
test_compiler_globals();
test_visitors();
test_semantic();
test_expression();
Expand Down

0 comments on commit 2fc0968

Please sign in to comment.