Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix issue 20810: Freshly built DMD fails to read config file #11111

Closed
wants to merge 1 commit into from

Conversation

AndrejMitrovic
Copy link
Contributor

According to MSDN docs the return value of GetFullPathName does not count the terminating null character on a successful call.

See here: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew

Note Although the return value in this case is a length that includes the terminating null character, the return value on success does not include the terminating null character in the count.

I'm not sure how this was never caught before though. But on my Win10 machine master fails.

Fixes https://issues.dlang.org/show_bug.cgi?id=20810

@dlang-bot
Copy link
Contributor

dlang-bot commented May 8, 2020

Thanks for your pull request, @AndrejMitrovic!

Bugzilla references

Auto-close Bugzilla Severity Description
20810 normal Freshly built DMD fails to read config file

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub run digger -- build "master + dmd#11111"

@@ -1005,10 +1005,13 @@ nothrow:
auto fullPath = (cast(wchar*) mem.xmalloc_noscan((fullPathLength + 1) * wchar.sizeof))[0 .. fullPathLength + 1];
scope(exit) mem.xfree(fullPath.ptr);

import core.stdc.stdio;

This comment was marked as resolved.

@AndrejMitrovic AndrejMitrovic force-pushed the fix-sc-ini branch 2 times, most recently from d4cbadd to f5c37cc Compare May 8, 2020 17:11
@Geod24
Copy link
Member

Geod24 commented May 8, 2020

Needs a test tho

@AndrejMitrovic
Copy link
Contributor Author

I'll see if I can add a test-case. It's coming from the call to usage(), so calling DMD with no params or probably --help. I'm guessing there's no such test in the test-suite.

@AndrejMitrovic
Copy link
Contributor Author

I added a test, but I haven't been able to unittest on Windows locally yet. There's some issue with the build.d script:

rdmd build.d unittest

...

 dmd.obj : error LNK2001: unresolved external symbol _D3dmd7backend8bcomplex12__ModuleInfoZ
C:\dev\dmd\generated\windows\release\64\dmd.exe-unittest : fatal error LNK1120: 1 unresolved externals

I'll try and sort this out soon.

@MoonlightSentinel
Copy link
Contributor

I added a test, but I haven't been able to unittest on Windows locally yet. There's some issue with the build.d script:

See #11112

@AndrejMitrovic
Copy link
Contributor Author

AndrejMitrovic commented May 9, 2020

It looks like the test-suite fails with the change. So it's not the appropriate fix.

I wonder if the bug is related to any recent Windows updates as I'm running v1909. But the only changes that are mentioned are for version 1607 in https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-getfullpathnamew.


int main()
{
run("$DMD"); // should print usage and exit with 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dmd without arguments returns exit code 1...

Suggested change
run("$DMD"); // should print usage and exit with 0
run("$DMD --help"); // should print usage and exit with 0

@MoonlightSentinel
Copy link
Contributor

MoonlightSentinel commented May 9, 2020

You could also try a compilable test as defined below.

EDIT: I would rather add the compilable test because it's also a proper test for dmd --help

/*
REQUIRED_ARGS: --help
PERMUTE_ARGS:
TEST_OUTPUT:
----
DMD64 D Compiler $r:.*$
Copyright (C) 1999-$n$ by The D Language Foundation, All Rights Reserved written by Walter Bright

Documentation: https://dlang.org/
Config file: 
Usage:
  dmd [<option>...] <file>...
  dmd [<option>...] -run <file> [<arg>...]

Where:
  <file>           D source file
  <arg>            Argument to pass when running the resulting program

<option>:
  @<cmdfile>       read arguments from cmdfile
  -allinst          generate code for all template instantiations
  -betterC          omit generating some runtime information and helper functions
  -boundscheck=[on|safeonly|off]
                    bounds checks on, in @safe only, or off
  -c                compile only, do not link
  -check=[assert|bounds|in|invariant|out|switch][=[on|off]]
                    enable or disable specific checks
  -check=[h|help|?] list information on all available checks
  -checkaction=[D|C|halt|context]
                    behavior on assert/boundscheck/finalswitch failure
  -checkaction=[h|help|?]
                    list information on all available check actions
  -color            turn colored console output on
  -color=[on|off|auto]
                    force colored console output on or off, or only when not redirected (default)
  -conf=<filename>  use config file at filename
  -cov              do code coverage analysis
  -cov=<nnn>        require at least nnn% code coverage
  -D                generate documentation
  -Dd<directory>    write documentation file to directory
  -Df<filename>     write documentation file to filename
  -d                silently allow deprecated features and symbols
  -de               issue an error when deprecated features or symbols are used (halt compilation)
  -dw               issue a message when deprecated features or symbols are used (default)
  -debug            compile in debug code
  -debug=<level>    compile in debug code <= level
  -debug=<ident>    compile in debug code identified by ident
  -debuglib=<name>  set symbolic debug library to name
  -defaultlib=<name>
                    set default library to name
  -deps             print module dependencies (imports/file/version/debug/lib)
  -deps=<filename>  write module dependencies to filename (only imports)
  -extern-std=<standard>
                    set C++ name mangling compatibility with <standard>
  -extern-std=[h|help|?]
                    list all supported standards
  -fPIC             generate position independent code
  -g                add symbolic debug info
  -gf               emit debug info for all referenced types
  -gs               always emit stack frame
  -gx               add stack stomp code
  -H                generate 'header' file
  -Hd=<directory>   write 'header' file to directory
  -Hf=<filename>    write 'header' file to filename
  -HC               generate C++ 'header' file
  -HCd=<directory>  write C++ 'header' file to directory
  -HCf=<filename>   write C++ 'header' file to filename
  --help            print help and exit
  -I=<directory>    look for imports also in directory
  -i[=<pattern>]    include imported modules in the compilation
  -ignore           ignore unsupported pragmas
  -inline           do function inlining
  -J=<directory>    look for string imports also in directory
  -L=<linkerflag>   pass linkerflag to link
  -lib              generate library rather than object files
  -lowmem           enable garbage collection for the compiler
  -m32              generate 32 bit code
  -m64              generate 64 bit code
  -main             add default main() (e.g. for unittesting)
  -man              open web browser on manual page
  -map              generate linker .map file
  -mcpu=<id>        generate instructions for architecture identified by 'id'
  -mcpu=[h|help|?]  list all architecture options
  -mixin=<filename> expand and save mixins to file specified by <filename>
  -mv=<package.module>=<filespec>
                    use <filespec> as source file for <package.module>
  -noboundscheck    no array bounds checking (deprecated, use -boundscheck=off)
  -O                optimize
  -o-               do not write object file
  -od=<directory>   write object & library files to directory
  -of=<filename>    name output file to filename
  -op               preserve source path for output files
  -preview=<id>     enable an upcoming language change identified by 'id'
  -preview=[h|help|?]
                    list all upcoming language changes
  -profile          profile runtime performance of generated code
  -profile=gc       profile runtime allocations
  -release          compile release version
  -revert=<id>      revert language change identified by 'id'
  -revert=[h|help|?]
                    list all revertable language changes
  -run <srcfile>    compile, link, and run the program srcfile
  -shared           generate shared library (DLL)
  -transition=<id>  help with language change identified by 'id'
  -transition=[h|help|?]
                    list all language changes
  -unittest         compile in unit tests
  -v                verbose
  -vcolumns         print character (column) numbers in diagnostics
  -verror-style=[digitalmars|gnu]
                    set the style for file/line number annotations on compiler messages
  -verrors=<num>    limit the number of error messages (0 means unlimited)
  -verrors=context  show error messages with the context of the erroring source line
  -verrors=spec     show errors from speculative compiles such as __traits(compiles,...)
  --version         print compiler version and exit
  -version=<level>  compile in version code >= level
  -version=<ident>  compile in version code identified by ident
  -vgc              list all gc allocations including hidden ones
  -vtls             list all variables going into thread local storage
  -w                warnings as errors (compilation will halt)
  -wi               warnings as messages (compilation will continue)
  -X                generate JSON file
  -Xf=<filename>    write JSON file to filename
  -Xcc=<driverflag> pass driverflag to linker driver (cc)
----
*/

@kinke
Copy link
Contributor

kinke commented May 10, 2020

I'm not sure how this was never caught before though. But on my Win10 machine master fails.

I've just refactored this and misread the docs, that's why. And canonicalName() is either unused during the whole testsuite, or no tested DMD built with enabled assertions.

Anyway, I think a little unittest would be the best way to test this.

According to MSDN docs, the return value of GetFullPathName
does *not* count the terminating null character.

In the first call, it *does* include this count because
a buffer was not specified in that initial call.

Fix Issue 20810
@AndrejMitrovic
Copy link
Contributor Author

I thought $r:.*$ would do substitution, but it doesn't.

And actually, I don't think this compilable test-case is correct. Because it's not testing the call properly. The sc.ini config path is empty here..

@MoonlightSentinel
Copy link
Contributor

I thought $r:.*$ would do substitution, but it doesn't.

It does, the problem lies in the platform specific options (and a whitespace error due to markdown).

And actually, I don't think this compilable test-case is correct. Because it's not testing the call properly. The sc.ini config path is empty here..

Actually, you're right because the test runner invokes dmd with -conf. Adding a unittest as @kinke
suggested should do the job.

Sorry for the distraction.

@AndrejMitrovic
Copy link
Contributor Author

Alright, I'll fix it up later.

Sorry for the distraction.

Not at all. Thanks for help from both of you!

@@ -0,0 +1,126 @@
/*
REQUIRED_ARGS: --help
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't use --help but pass a simple module containing an empty main func. The use of --help is, in addition of not testing the right thing, something that would have to be maintained over years.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't use --help but pass a simple module containing an empty main func. The use of --help is, in addition of not testing the right thing.

Not an ideal test but running dmd --help triggers that bug.

something that would have to be maintained over years.

Only the current version, I'll re-enable a maintenance free version after this PR is merged.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A brittle integration test for this is overkill; a trivial little unittest would do the job perfectly, just like

dmd/src/dmd/root/filename.d

Lines 363 to 370 in 77ae162

unittest
{
version (Windows)
assert(combine("foo"[], "bar"[]) == "foo\\bar");
else
assert(combine("foo"[], "bar"[]) == "foo/bar");
assert(combine("foo/"[], "bar"[]) == "foo/bar");
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, a unittest is the best solution here.

@MoonlightSentinel
Copy link
Contributor

Any updates @AndrejMitrovic ?

@AndrejMitrovic
Copy link
Contributor Author

Well it seems that master works with your test, so it looks like the issue might be somewhere else?

@MoonlightSentinel
Copy link
Contributor

it fails with current master, the PR was accidentally merged by dlang-bot and got reverted.

@AndrejMitrovic
Copy link
Contributor Author

I'll close this since I can't reproduce it anymore, sorry.

kinke added a commit to kinke/dmd that referenced this pull request Jun 18, 2020
The assertion was wrong and guaranteed to fail when enabled (my bad).
This is a reboot of dlang#11111.

Also make sure to return a new root.rmem-managed memory allocation in
all cases, i.e., not the malloc'd memory directly for the
canonicalize_file_name version. E.g., the memory is released via
mem.xfree() in FileName.safeSearchPath().
kinke added a commit to kinke/dmd that referenced this pull request Jun 18, 2020
The assertion was wrong and guaranteed to fail when enabled (my bad).
This is a reboot of dlang#11111.

Also make sure to return a new root.rmem-managed memory allocation in
all cases, i.e., not the malloc'd memory directly for the
canonicalize_file_name version. E.g., the memory is released via
mem.xfree() in FileName.safeSearchPath().
kinke added a commit to kinke/dmd that referenced this pull request Jun 18, 2020
The assertion was wrong and guaranteed to fail when enabled (my bad).
This is a reboot of dlang#11111.

Also make sure to return a new root.rmem-managed memory allocation in
all cases, i.e., not the malloc'd memory directly for the
canonicalize_file_name version. E.g., the memory is released via
mem.xfree() in FileName.safeSearchPath().
kinke added a commit to kinke/dmd that referenced this pull request Jun 18, 2020
The assertion was wrong and guaranteed to fail when enabled (my bad).
This is a reboot of dlang#11111.

Also make sure to return a new root.rmem-managed memory allocation in
all cases, i.e., not the malloc'd memory directly for the
canonicalize_file_name version. E.g., the memory is released via
mem.xfree() in FileName.safeSearchPath().
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants