The default base address for an .exe built in Visual Studio is 0x00400000.
The default base address for d3dx9_30.dll and odbcint.dll (which both live in %windir%\system32) is also 0x00400000. So by default, exes that link to either of these dlls will have a runtime address collision. The OS automatically relocates the dll to a different base addresses and fixes up pointers as needed, and I can see this happening when I attach the VS debugger: The relocated module gets an exclamation icon overlay.
Rebasing system DLLs is a really bad idea, not to mention nearly impossible to do on user systems. So I have decided to rebase my exes to prevent this address collision and thus prevent runtime rebasing.
If I change my client EXE to a different base address to move it out of d3dx9_30.dll's way, it works fine: no address collision, no relocation, no fixups.
But if I change my server EXEs to a different base address to move them out of odbcint.dll's way, it does not work.
odbcint.dll is 0x17000 bytes in memory and prefers base address 0x00400000. I tried basing my EXEs at 0x00420000, then at 0x00660000. Still odbcint.dll gets relocated at runtime. I profiled with depends.exe, which showed that there is no other module attempting to claim this address before odbcint.dll loads.
Does anyone have a theory explaining why I can't get odbcint.dll to load at its preferred address?
Update:
vadump shows that by the time I enter main() the memory at 0x00400000-0x00470000 is claimed as 'UNKNOWN_MAPPED'. I have been unable to find more information about what exactly this means. I presume that some system dll is reserving this memory at load time; my debugging-fu is not strong enough to discover which, why, or precisely when.
If you download VADump (available in the Windows Resource Kit:), you can see exactly what module is hitting those pages and causing it to miss its address. (Run vadump -op pid.)
You didn't say what OS you're working on, but on Vista/2K8+ you should also know about ASLR.
Related
Maybe it's a newbie CP/M question, but anyway ... Is it possible to relocate CP/M BDOS? I have a hardware I've written BIOS for, to be able to use with CPM 2.2. However that BDOS (seen by disassembling it) uses fixed addresses. Since I don't know CP/M to well, I have no idea how to place CP/M BDOS to another start address. The only (somewhat ugly!) solution I could figure out: I found a CP/M disassembly list, so I've simply modified the "ORG" directive and I re-assembled it. Is there any other way, eg some CP/M utilty? And if so, how it can do that, since BDOS uses JP, CALL etc opcodes (sorry I am just familiar with Z80, not so much with original 8080 assembly) so it's not simply PC independent. Thanks!
No need for a disassembly; the original CP/M source code is available (and, yes, BDOS and everything else resident is assembly, not PL/M). Within the "CP/M 2.2 ORIGINAL SOURCE" offered there you should find both OS3BDOS.ASM and OS3BDOS1.ASM. These are both different released versions of the CP/M 2.2 BDOS source (see README.TXT); you should be able to adjust the org and rebuild either of them, using the assembler also provided in the archive.
Alternatively you can use the MOVCPM tool (also included in the archive). It's intended to relocate the BDOS and the supplied BIOS but there's nothing to stop you replacing the BIOS after the fact.
Possibly of interest to you if you'd prefer to write a cross-relocator: from a quick bit of research, the interesting bit is this from the BDOS source:
if test
org 0dc00h
else
org 0800h
endif
Why would the BDOS ever be at 0800 on any useful machine? Why is dc00 a 'test' address? Because the relocation is handled very trivially: BDOS is built once at 0800 and once at dc00. Through a binary compare of those two builds any differences must be where correct addresses need to be inserted, and the difference from the original org value tells you how to calculate the value to insert.
My firm's Access database has been having some serious problems recently. The errors we're getting seem like they indicate corruption -- here are the most common:
Error accessing file. Network connection may have been lost.
There was an error compiling this function.
No error, Access just crashes completely.
I've noticed that these errors only happen with a compiled database. If I decompile it, it works fine. If I take an uncompiled database and compile it, it works fine -- until the next time I try to open it. It appears that compiling the database into a .ACCDE file solves the problem, which is what I've been doing, but one person has reported that the issue returned for her, which has me very nervous.
I've tried exporting all of the objects in the database to text, starting with a brand new database, and importing them all again, but that doesn't solve the problem. Once I import all of the objects into the clean database, the problem comes back.
One last point that seems be related, but I don't understand how. The problem started right around the time that I added some class modules to the database. These class modules use the VBA Implements keyword, in an effort to clean up my code by introducing some polymorphism. I don't know why this would cause the problem, but the timing seems to indicate a relationship.
I've been searching for an explanation, but haven't found one yet. Does anyone have any suggestions?
EDIT: The database includes a few references in addition to the standard ones:
Microsoft ActiveX Data Objects 2.8
Microsoft Office 12.0
Microsoft Scripting Runtime
Microsoft VBScript Regular Expressions 5.5
Some of the things I do and use when debugging Access:
Test my app in a number of VM. You can use HyperV on Win8, VMWare or VirtualBox to set up various controlled test environments, like testing on WinXP, Win7, Win8, 32bit or 64 bits, just anything that matches the range of OS and bitness of your users.
I use vbWatchDog, a clever utility that only adds a few classes to your application (no external dependency) and allows you to trap errors at high level, and show you exactly where they happen. This is invaluable to catch and record strange errors, especially in the field.
If the issue appears isolated to one or a few users only, I would try to find out what is special about their config. If nothing seems out of place, I would completely unsintall all Office component and re-install it after scrubbing the registry for dangling keys and removing all traces of folders from the old install.
If your users do not need a complete version of Access, just use the free Access Runtime on their machine.
Make sure that you are using consistent versions of Access throughout: if you are using Access 2007, make sure your dev machine is also using that version and that all other users are also only using that version and that no components from Access 2010/2013 are present.
Try to ascertain if the crash is always happening around the same user-actions. I use a simple log file that I write to when a debugging flag is set. The log file is a simple text file that I open/write to/close everytime I log something (I don't keep it open to make sure the data is flushed to the file, otherwise when Access crashes, you may only have old data in the log file as the new one may still be in the buffer). Things I log are, for instance, sensitive function entry/exit, SQL queries that I execute from code, form open/close, etc.
As a generality, make sure your app compiles without issue (I mean when doing Debug > Compile from the IDE). Any issue at this stage must be solved.
Make absolutely sure you close all open recordsets, preferrably followed by setting their variables to Nothing. VBA is not as sensitive as it used to be about dangling references, but I found it good practice, especially when you cannot be absolutely sure that these references will be freed (especially when doing stuff at Module-level or Class-level for instance, where the scope may be longer-lived than expected).
Similarly, make sure you properly destroy any COM object you create in your classes (and subs/functions. The Class_Terminate destructor must explicitly clean up all. This is also valid when closing forms if you created COM objects (you mentioned using ADOX, scripting objects and regex). In general keeping track of created objects is paramount: make sure you explicitly free all your objects by resetting them (for instance using RemoveAll on a dictionary, then assigning their reference to Nothing.
Do not over-use On Error Resume or On Error Goto. I almost never use these except when absolutely necessary to recover from otherwise undetectable errors. Using these error trapping constructs can hide a lot of errors that would otherwise show you that something is wrong with your code. I prefer to program defensively than having to handle exceptions.
For testing, disable your error trapping to see if it isn't hiding the cause of your crashes.
Make sure that the front-end is local to the user machine, You mention they get their individual front-end from the network but I'm not sure if they run it from there or if it it copied on their local machine. At any rate, it should be local not on a remote folder.
You mention using SQL Server as a backend. Try to trace all the queries being executed. It's possible that the issue comes from communication with SQL Server, a corrupt driver, a security issue that prevents some queries from being run, a query returning unexpected data, etc. Watch the log files and event log on the server closely for strange errors, especially if they involve security.
Speaking of event log, look for the trace of the crash in the event log of your users. There may be information there, however cryptic.
If you use custom ribbon actions, make sure thy are not causing issues. I had strange problems over time with the ribbon. Log all all function calls made by the ribbon.
I compile a DLL with mingw 4.5.0 and use it as a Game Maker 8.0 extension. Game Maker dynamically loads the dll. Everything appears to work (the dll functions are called and provide correct return values), but when I close Game Maker a dialog pops up: "Microsoft Visual C++ Runtime Library", "This application has requested the Runtime to terminate in an unusual way." After that, the process continues to linger in the background for a few seconds and then disappears.
This also happens when none of the functions of the dll are actually called. There is no DllMain, and all static/global variables are basic data types or std::string (it actually also happens when I remove the std::strings).
The dll statically links with zlib and libpng. The problem seems to vanish when I pass -static to the linker which (I assume) also links the runtime statically. However, this considerably inflates the size of my DLL, and it is at best a workaround until I understand what is going on.
Any ideas on what might be the cause?
Update: Actually, it seems that the problem only happens when two extensons are loaded in Game Maker: One with a dll linked with -static, and the other without. Linking both without -static makes the problem disappear. However, I still don't understand the problem, because the dlls never directly interact or share data structures.
Update 2: I recently found out that this might be related to strange behavior of Game Maker itself. It seems that global variables aren't initialized correctly when the DLL is loaded, which might cause a crash on unloading if global objects try to free memory they don't own. That would mean the -static was just a random factor that changed the value of the uninitialized memory the globals were associated with.
Update 3: Modified the above to include the info that this is about Game Maker extensions, since this is likely relevant as per Update 2.
It's just a guess. Try to look into something like the "static initialization order fiasco" that is described here. It may be that your problem is more related to the destructors (since it happens on close).
Here's an obscure Friday Morning question:
Is it possible in LabVIEW to get the callees of a VI without loading the entire VI into memory? For instance, by reading static information from the binary?
Thanks
Well there is the private/scriptig method App.Read Linker Info From File, I don't think this will load the VI into memory, for more info have a look at the LabVIEW wiki (currently off-line , here is a Google cached page) page on the linker method.
The linker method will return all the info on the VI and it's external needs (VIs, DLLs, CHMs etc).
Ton
No, I don't believe so. When you open a reference to the top-level VI, it will be loaded into memory. That's even before you have the opportunity to query it for its callees.
Ton's answer is correct. The mentioned method is an application instance method not a VI reference method. You supply the path to the VI in question to that method and it will then parse the VI structure and extract all the relevant linker information without loading the VI as such into memory (Obviously it will read in the information from the file into memory to parse it but it will not load/instantiate the VI itself).
The problem with that node is however that it is private, because it has changed its interface in the past and may do so in the future again without warning. There even was a case between 7.0 and 7.1 or so, where the interface changed without any warning in the form of a broken arrow, but when executing it with the old data structure it would simply crash. As a private node that is fully valid, as no warranties are made about the functionality of private nodes.
I'm new to VB6 but i'm currently in charge of maintaining a horror of editor like tool with plenty of forms, classes, modules and 3rd party tools all chunk together like the skin faces on that guy in the texas chainsaw massacre...
What i don't understand is why i get different results when i run the app in debugging mode, vs when i compiled it and run it on my devevelopment pc vs when i installed it on a different pc.
Yes i know i'm dumb, so please direct me to where i can find out more about this. I'm hoping to find out something like different linking, registry related etc connection that i'm simply not getting right now, i.e. something like wax on, wax off :P
The main pain in the neck is when i'm trying to debug some errors from my QA and i need to find a spare pc to test this on plus i can't directly debug because i don't know where the code is if i do it that manner.
Thanks.
i run the app in debugging mode vs when i compiled it and run it on my
devevelopment pc
When you compile you have the option of compiling to native code or pcode. The debugger runs using pcode only. Under rare circumstances when you compile to native code there will be a change in behavior. This particular is really rare. I used VB6 since it's release and I may get it once or twice a year. My application is a complex CAD/CAM creating shapes and running metal cutting machine and has two dozen DLLs. Not a typical situation. At home with my hobby software I never ran into this problem.
There are another class of errors that result from event sequencing problems. While VB6 isn't truly multi-tasking it has the ability to jump out of the current code block to process a event. If it re-enters the same block for the new event interesting things (to say the least) can result. I think this is the likely source of your problems as you software is an editor which is a highly interactive type of software.
In general the problem is fixed by reordering the effected areas. You find the effected area by inserting MsgBox or write to a text file to log where you are. I recommend logging to a text file as MsgBox tend to alter behavior that are timing or multi-tasking related.
Remember if a event fire while VB6 in the middle of a code block and there a DoEvents floating around then it will leave the code block process the event and return to the original code block. If it re-enters the same code block and you didn't mean for this to happen then you will have problems. And you will have different problems on different computers as the timing will be different for each.
The easiest way to deal with this type of issues is create some flag variables. In multi-tasking parlance they are known as semaphores or mutexes. WHen you enter a critical section of code, you set it true. When you leave the routine you set it to false. If it is already true when you enter that section of code you don't execute it.
when i installed it on a different pc.
These are usually the result of the wrong DLL installed. Most likely you have an older version while the target has a newer version. I would download the free Virtual PC and create a clean Window XP install to double check this.
If your problem is event timing this too can be different on different computers. This is found by logging (not MsgBox) suspect regions.
If you can display a screen shot or the text of your specific errors then I can help better.
The first thing to check would be the versions of all the dlls that your app depends on - including the service pack version of the VB6 dll.
Have you any more specific details about what's behaving differently?