Testing whether to launch debugger based on build & command line arguments

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
1
down vote

favorite












I have a C# application that may be spawned by another process using Shell or its equivalent. As such, it is not trivial to simply F5 into a breakpoint nor launching an external program will work since a brand new process get spawned. Thus it is problematic especially when doing integration tests or diagnosing unusual problem that requires the same context than the one provided by automated tests.



I thought of passing in a debug flag but I don't want it to be accepted in a release build. I adapted the code from this SO thread by making it a complete function that returns a private struct. The important part is the check within the Main procedure where we inspect whether a -debug flag has been passed via the command line argument and if so, confirm this is a debug build, not a release build. This seems to work well enough; but I want to know if this is reasonably good way to enable debugging on demand without exposing too much. Thus, the review is to see if this could be improved upon:



Note: I don't currently use all the member of the struct in the code; I don't know if there may be other use yet and didn't bother eliminating the unused members.



Note #2: I belatedly realized that I could have wrapped the check and the supporting function inside a #if DEBUG block, which would also prevent the code from ever being included in a release build. However, it got me thinking if there might be legitimate scenario to launch debugger on a release build (even though the debug information will be sparse due to optimizations), so we can leave the question with the expectation that it could be used in release. Would it be an acceptable way or are there better ways?



internal class Program

[STAThread]
private static int Main(string args)

if (args.Any(a => a == "--debug") && GetDebugData().BuildType.ToLowerInvariant() == "debug")

Debugger.Launch();


// do something interesting....


private struct AssemblyDebugData

internal bool HasDebuggableAttribute;
internal bool IsJITOptimized;
internal string BuildType;
internal string DebugOutput;


private static AssemblyDebugData GetDebugData()

AssemblyDebugData result = new AssemblyDebugData();

object attribs = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(DebuggableAttribute), false);

// If the 'DebuggableAttribute' is not found then it is definitely an OPTIMIZED build
if (attribs.Length > 0)

// Just because the 'DebuggableAttribute' is found doesn't necessarily mean
// it's a DEBUG build; we have to check the JIT Optimization flag
// i.e. it could have the "generate PDB" checked but have JIT Optimization enabled
DebuggableAttribute debuggableAttribute = attribs[0] as DebuggableAttribute;
if (debuggableAttribute != null)

result.HasDebuggableAttribute = true;
result.IsJITOptimized = !debuggableAttribute.IsJITOptimizerDisabled;
result.BuildType = debuggableAttribute.IsJITOptimizerDisabled ? "Debug" : "Release";

// check for Debug Output "full" or "pdb-only"
result.DebugOutput = (debuggableAttribute.DebuggingFlags &
DebuggableAttribute.DebuggingModes.Default) !=
DebuggableAttribute.DebuggingModes.None
? "Full" : "pdb-only";


else

result.IsJITOptimized = true;
result.BuildType = "Release";


return result;








share|improve this question



























    up vote
    1
    down vote

    favorite












    I have a C# application that may be spawned by another process using Shell or its equivalent. As such, it is not trivial to simply F5 into a breakpoint nor launching an external program will work since a brand new process get spawned. Thus it is problematic especially when doing integration tests or diagnosing unusual problem that requires the same context than the one provided by automated tests.



    I thought of passing in a debug flag but I don't want it to be accepted in a release build. I adapted the code from this SO thread by making it a complete function that returns a private struct. The important part is the check within the Main procedure where we inspect whether a -debug flag has been passed via the command line argument and if so, confirm this is a debug build, not a release build. This seems to work well enough; but I want to know if this is reasonably good way to enable debugging on demand without exposing too much. Thus, the review is to see if this could be improved upon:



    Note: I don't currently use all the member of the struct in the code; I don't know if there may be other use yet and didn't bother eliminating the unused members.



    Note #2: I belatedly realized that I could have wrapped the check and the supporting function inside a #if DEBUG block, which would also prevent the code from ever being included in a release build. However, it got me thinking if there might be legitimate scenario to launch debugger on a release build (even though the debug information will be sparse due to optimizations), so we can leave the question with the expectation that it could be used in release. Would it be an acceptable way or are there better ways?



    internal class Program

    [STAThread]
    private static int Main(string args)

    if (args.Any(a => a == "--debug") && GetDebugData().BuildType.ToLowerInvariant() == "debug")

    Debugger.Launch();


    // do something interesting....


    private struct AssemblyDebugData

    internal bool HasDebuggableAttribute;
    internal bool IsJITOptimized;
    internal string BuildType;
    internal string DebugOutput;


    private static AssemblyDebugData GetDebugData()

    AssemblyDebugData result = new AssemblyDebugData();

    object attribs = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(DebuggableAttribute), false);

    // If the 'DebuggableAttribute' is not found then it is definitely an OPTIMIZED build
    if (attribs.Length > 0)

    // Just because the 'DebuggableAttribute' is found doesn't necessarily mean
    // it's a DEBUG build; we have to check the JIT Optimization flag
    // i.e. it could have the "generate PDB" checked but have JIT Optimization enabled
    DebuggableAttribute debuggableAttribute = attribs[0] as DebuggableAttribute;
    if (debuggableAttribute != null)

    result.HasDebuggableAttribute = true;
    result.IsJITOptimized = !debuggableAttribute.IsJITOptimizerDisabled;
    result.BuildType = debuggableAttribute.IsJITOptimizerDisabled ? "Debug" : "Release";

    // check for Debug Output "full" or "pdb-only"
    result.DebugOutput = (debuggableAttribute.DebuggingFlags &
    DebuggableAttribute.DebuggingModes.Default) !=
    DebuggableAttribute.DebuggingModes.None
    ? "Full" : "pdb-only";


    else

    result.IsJITOptimized = true;
    result.BuildType = "Release";


    return result;








    share|improve this question























      up vote
      1
      down vote

      favorite









      up vote
      1
      down vote

      favorite











      I have a C# application that may be spawned by another process using Shell or its equivalent. As such, it is not trivial to simply F5 into a breakpoint nor launching an external program will work since a brand new process get spawned. Thus it is problematic especially when doing integration tests or diagnosing unusual problem that requires the same context than the one provided by automated tests.



      I thought of passing in a debug flag but I don't want it to be accepted in a release build. I adapted the code from this SO thread by making it a complete function that returns a private struct. The important part is the check within the Main procedure where we inspect whether a -debug flag has been passed via the command line argument and if so, confirm this is a debug build, not a release build. This seems to work well enough; but I want to know if this is reasonably good way to enable debugging on demand without exposing too much. Thus, the review is to see if this could be improved upon:



      Note: I don't currently use all the member of the struct in the code; I don't know if there may be other use yet and didn't bother eliminating the unused members.



      Note #2: I belatedly realized that I could have wrapped the check and the supporting function inside a #if DEBUG block, which would also prevent the code from ever being included in a release build. However, it got me thinking if there might be legitimate scenario to launch debugger on a release build (even though the debug information will be sparse due to optimizations), so we can leave the question with the expectation that it could be used in release. Would it be an acceptable way or are there better ways?



      internal class Program

      [STAThread]
      private static int Main(string args)

      if (args.Any(a => a == "--debug") && GetDebugData().BuildType.ToLowerInvariant() == "debug")

      Debugger.Launch();


      // do something interesting....


      private struct AssemblyDebugData

      internal bool HasDebuggableAttribute;
      internal bool IsJITOptimized;
      internal string BuildType;
      internal string DebugOutput;


      private static AssemblyDebugData GetDebugData()

      AssemblyDebugData result = new AssemblyDebugData();

      object attribs = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(DebuggableAttribute), false);

      // If the 'DebuggableAttribute' is not found then it is definitely an OPTIMIZED build
      if (attribs.Length > 0)

      // Just because the 'DebuggableAttribute' is found doesn't necessarily mean
      // it's a DEBUG build; we have to check the JIT Optimization flag
      // i.e. it could have the "generate PDB" checked but have JIT Optimization enabled
      DebuggableAttribute debuggableAttribute = attribs[0] as DebuggableAttribute;
      if (debuggableAttribute != null)

      result.HasDebuggableAttribute = true;
      result.IsJITOptimized = !debuggableAttribute.IsJITOptimizerDisabled;
      result.BuildType = debuggableAttribute.IsJITOptimizerDisabled ? "Debug" : "Release";

      // check for Debug Output "full" or "pdb-only"
      result.DebugOutput = (debuggableAttribute.DebuggingFlags &
      DebuggableAttribute.DebuggingModes.Default) !=
      DebuggableAttribute.DebuggingModes.None
      ? "Full" : "pdb-only";


      else

      result.IsJITOptimized = true;
      result.BuildType = "Release";


      return result;








      share|improve this question













      I have a C# application that may be spawned by another process using Shell or its equivalent. As such, it is not trivial to simply F5 into a breakpoint nor launching an external program will work since a brand new process get spawned. Thus it is problematic especially when doing integration tests or diagnosing unusual problem that requires the same context than the one provided by automated tests.



      I thought of passing in a debug flag but I don't want it to be accepted in a release build. I adapted the code from this SO thread by making it a complete function that returns a private struct. The important part is the check within the Main procedure where we inspect whether a -debug flag has been passed via the command line argument and if so, confirm this is a debug build, not a release build. This seems to work well enough; but I want to know if this is reasonably good way to enable debugging on demand without exposing too much. Thus, the review is to see if this could be improved upon:



      Note: I don't currently use all the member of the struct in the code; I don't know if there may be other use yet and didn't bother eliminating the unused members.



      Note #2: I belatedly realized that I could have wrapped the check and the supporting function inside a #if DEBUG block, which would also prevent the code from ever being included in a release build. However, it got me thinking if there might be legitimate scenario to launch debugger on a release build (even though the debug information will be sparse due to optimizations), so we can leave the question with the expectation that it could be used in release. Would it be an acceptable way or are there better ways?



      internal class Program

      [STAThread]
      private static int Main(string args)

      if (args.Any(a => a == "--debug") && GetDebugData().BuildType.ToLowerInvariant() == "debug")

      Debugger.Launch();


      // do something interesting....


      private struct AssemblyDebugData

      internal bool HasDebuggableAttribute;
      internal bool IsJITOptimized;
      internal string BuildType;
      internal string DebugOutput;


      private static AssemblyDebugData GetDebugData()

      AssemblyDebugData result = new AssemblyDebugData();

      object attribs = Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(DebuggableAttribute), false);

      // If the 'DebuggableAttribute' is not found then it is definitely an OPTIMIZED build
      if (attribs.Length > 0)

      // Just because the 'DebuggableAttribute' is found doesn't necessarily mean
      // it's a DEBUG build; we have to check the JIT Optimization flag
      // i.e. it could have the "generate PDB" checked but have JIT Optimization enabled
      DebuggableAttribute debuggableAttribute = attribs[0] as DebuggableAttribute;
      if (debuggableAttribute != null)

      result.HasDebuggableAttribute = true;
      result.IsJITOptimized = !debuggableAttribute.IsJITOptimizerDisabled;
      result.BuildType = debuggableAttribute.IsJITOptimizerDisabled ? "Debug" : "Release";

      // check for Debug Output "full" or "pdb-only"
      result.DebugOutput = (debuggableAttribute.DebuggingFlags &
      DebuggableAttribute.DebuggingModes.Default) !=
      DebuggableAttribute.DebuggingModes.None
      ? "Full" : "pdb-only";


      else

      result.IsJITOptimized = true;
      result.BuildType = "Release";


      return result;










      share|improve this question












      share|improve this question




      share|improve this question








      edited Mar 21 at 1:54









      Hosch250

      16.9k561153




      16.9k561153









      asked Mar 20 at 2:35









      this

      1,232317




      1,232317




















          1 Answer
          1






          active

          oldest

          votes

















          up vote
          2
          down vote



          accepted










          1. Use #if Debug. It will be a lot more expected to have to remove/disable that than to change the if and remember to remove the then-dead GetDebugData method. (Principle of Least Astonishment, right?)


          2. Don't specify STAThread. It's just useless. First, it would be extremely surprising if someone tries to use multithreading 10 years down the road and it failed. Second, it doesn't provide any significant overhead (if any at all) to not use this. Finally, console apps run single-threaded by default. There is no excuse to disable multi-threading in the whole app. There is excuse to disable multi-threading in parts that can't be multi-threaded because of whatever (maybe it calls into code running on a STA thread), but those instances can be handled on a case-by-case basis with explanation in comments.


          Now, assuming for some reason I haven't comprehended, you absolutely have to use this.



          1. You are defining whether a build is a "debug" or "release" based on whether the code is optimized. That has nothing to do with Visual Studio's definition (and therefore the standard definition) of what a "debug" or "release" build is. That and the output paths are the only changes I can think of off-hand between the default "debug" and "release" candidates. However, you could define a "debug" build as one compiled against C# 7.2 and a "release" build as one compiled against C# 6 and leave optimization on or off in both for whatever reason. I wouldn't use the terminology "debug" vs. "release" here; I'd just check whether debug symbols were enabled when I determined whether to kick off the debugger.

          2. If you change what I suggest above, I'd recommend renaming DebugOutput to just Output and assigning it whether the code is optimized or not. I can compile as None, Full, Pdb-Only, Portable, or Embedded with JIT-optimization enabled anyway.





          share|improve this answer





















            Your Answer




            StackExchange.ifUsing("editor", function ()
            return StackExchange.using("mathjaxEditing", function ()
            StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
            StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
            );
            );
            , "mathjax-editing");

            StackExchange.ifUsing("editor", function ()
            StackExchange.using("externalEditor", function ()
            StackExchange.using("snippets", function ()
            StackExchange.snippets.init();
            );
            );
            , "code-snippets");

            StackExchange.ready(function()
            var channelOptions =
            tags: "".split(" "),
            id: "196"
            ;
            initTagRenderer("".split(" "), "".split(" "), channelOptions);

            StackExchange.using("externalEditor", function()
            // Have to fire editor after snippets, if snippets enabled
            if (StackExchange.settings.snippets.snippetsEnabled)
            StackExchange.using("snippets", function()
            createEditor();
            );

            else
            createEditor();

            );

            function createEditor()
            StackExchange.prepareEditor(
            heartbeatType: 'answer',
            convertImagesToLinks: false,
            noModals: false,
            showLowRepImageUploadWarning: true,
            reputationToPostImages: null,
            bindNavPrevention: true,
            postfix: "",
            onDemand: true,
            discardSelector: ".discard-answer"
            ,immediatelyShowMarkdownHelp:true
            );



            );








             

            draft saved


            draft discarded


















            StackExchange.ready(
            function ()
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f189992%2ftesting-whether-to-launch-debugger-based-on-build-command-line-arguments%23new-answer', 'question_page');

            );

            Post as a guest






























            1 Answer
            1






            active

            oldest

            votes








            1 Answer
            1






            active

            oldest

            votes









            active

            oldest

            votes






            active

            oldest

            votes








            up vote
            2
            down vote



            accepted










            1. Use #if Debug. It will be a lot more expected to have to remove/disable that than to change the if and remember to remove the then-dead GetDebugData method. (Principle of Least Astonishment, right?)


            2. Don't specify STAThread. It's just useless. First, it would be extremely surprising if someone tries to use multithreading 10 years down the road and it failed. Second, it doesn't provide any significant overhead (if any at all) to not use this. Finally, console apps run single-threaded by default. There is no excuse to disable multi-threading in the whole app. There is excuse to disable multi-threading in parts that can't be multi-threaded because of whatever (maybe it calls into code running on a STA thread), but those instances can be handled on a case-by-case basis with explanation in comments.


            Now, assuming for some reason I haven't comprehended, you absolutely have to use this.



            1. You are defining whether a build is a "debug" or "release" based on whether the code is optimized. That has nothing to do with Visual Studio's definition (and therefore the standard definition) of what a "debug" or "release" build is. That and the output paths are the only changes I can think of off-hand between the default "debug" and "release" candidates. However, you could define a "debug" build as one compiled against C# 7.2 and a "release" build as one compiled against C# 6 and leave optimization on or off in both for whatever reason. I wouldn't use the terminology "debug" vs. "release" here; I'd just check whether debug symbols were enabled when I determined whether to kick off the debugger.

            2. If you change what I suggest above, I'd recommend renaming DebugOutput to just Output and assigning it whether the code is optimized or not. I can compile as None, Full, Pdb-Only, Portable, or Embedded with JIT-optimization enabled anyway.





            share|improve this answer

























              up vote
              2
              down vote



              accepted










              1. Use #if Debug. It will be a lot more expected to have to remove/disable that than to change the if and remember to remove the then-dead GetDebugData method. (Principle of Least Astonishment, right?)


              2. Don't specify STAThread. It's just useless. First, it would be extremely surprising if someone tries to use multithreading 10 years down the road and it failed. Second, it doesn't provide any significant overhead (if any at all) to not use this. Finally, console apps run single-threaded by default. There is no excuse to disable multi-threading in the whole app. There is excuse to disable multi-threading in parts that can't be multi-threaded because of whatever (maybe it calls into code running on a STA thread), but those instances can be handled on a case-by-case basis with explanation in comments.


              Now, assuming for some reason I haven't comprehended, you absolutely have to use this.



              1. You are defining whether a build is a "debug" or "release" based on whether the code is optimized. That has nothing to do with Visual Studio's definition (and therefore the standard definition) of what a "debug" or "release" build is. That and the output paths are the only changes I can think of off-hand between the default "debug" and "release" candidates. However, you could define a "debug" build as one compiled against C# 7.2 and a "release" build as one compiled against C# 6 and leave optimization on or off in both for whatever reason. I wouldn't use the terminology "debug" vs. "release" here; I'd just check whether debug symbols were enabled when I determined whether to kick off the debugger.

              2. If you change what I suggest above, I'd recommend renaming DebugOutput to just Output and assigning it whether the code is optimized or not. I can compile as None, Full, Pdb-Only, Portable, or Embedded with JIT-optimization enabled anyway.





              share|improve this answer























                up vote
                2
                down vote



                accepted







                up vote
                2
                down vote



                accepted






                1. Use #if Debug. It will be a lot more expected to have to remove/disable that than to change the if and remember to remove the then-dead GetDebugData method. (Principle of Least Astonishment, right?)


                2. Don't specify STAThread. It's just useless. First, it would be extremely surprising if someone tries to use multithreading 10 years down the road and it failed. Second, it doesn't provide any significant overhead (if any at all) to not use this. Finally, console apps run single-threaded by default. There is no excuse to disable multi-threading in the whole app. There is excuse to disable multi-threading in parts that can't be multi-threaded because of whatever (maybe it calls into code running on a STA thread), but those instances can be handled on a case-by-case basis with explanation in comments.


                Now, assuming for some reason I haven't comprehended, you absolutely have to use this.



                1. You are defining whether a build is a "debug" or "release" based on whether the code is optimized. That has nothing to do with Visual Studio's definition (and therefore the standard definition) of what a "debug" or "release" build is. That and the output paths are the only changes I can think of off-hand between the default "debug" and "release" candidates. However, you could define a "debug" build as one compiled against C# 7.2 and a "release" build as one compiled against C# 6 and leave optimization on or off in both for whatever reason. I wouldn't use the terminology "debug" vs. "release" here; I'd just check whether debug symbols were enabled when I determined whether to kick off the debugger.

                2. If you change what I suggest above, I'd recommend renaming DebugOutput to just Output and assigning it whether the code is optimized or not. I can compile as None, Full, Pdb-Only, Portable, or Embedded with JIT-optimization enabled anyway.





                share|improve this answer













                1. Use #if Debug. It will be a lot more expected to have to remove/disable that than to change the if and remember to remove the then-dead GetDebugData method. (Principle of Least Astonishment, right?)


                2. Don't specify STAThread. It's just useless. First, it would be extremely surprising if someone tries to use multithreading 10 years down the road and it failed. Second, it doesn't provide any significant overhead (if any at all) to not use this. Finally, console apps run single-threaded by default. There is no excuse to disable multi-threading in the whole app. There is excuse to disable multi-threading in parts that can't be multi-threaded because of whatever (maybe it calls into code running on a STA thread), but those instances can be handled on a case-by-case basis with explanation in comments.


                Now, assuming for some reason I haven't comprehended, you absolutely have to use this.



                1. You are defining whether a build is a "debug" or "release" based on whether the code is optimized. That has nothing to do with Visual Studio's definition (and therefore the standard definition) of what a "debug" or "release" build is. That and the output paths are the only changes I can think of off-hand between the default "debug" and "release" candidates. However, you could define a "debug" build as one compiled against C# 7.2 and a "release" build as one compiled against C# 6 and leave optimization on or off in both for whatever reason. I wouldn't use the terminology "debug" vs. "release" here; I'd just check whether debug symbols were enabled when I determined whether to kick off the debugger.

                2. If you change what I suggest above, I'd recommend renaming DebugOutput to just Output and assigning it whether the code is optimized or not. I can compile as None, Full, Pdb-Only, Portable, or Embedded with JIT-optimization enabled anyway.






                share|improve this answer













                share|improve this answer



                share|improve this answer











                answered Mar 21 at 1:52









                Hosch250

                16.9k561153




                16.9k561153






















                     

                    draft saved


                    draft discarded


























                     


                    draft saved


                    draft discarded














                    StackExchange.ready(
                    function ()
                    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f189992%2ftesting-whether-to-launch-debugger-based-on-build-command-line-arguments%23new-answer', 'question_page');

                    );

                    Post as a guest













































































                    Popular posts from this blog

                    Greedy Best First Search implementation in Rust

                    Function to Return a JSON Like Objects Using VBA Collections and Arrays

                    C++11 CLH Lock Implementation