I have to port some legacy software written in ADA from Windows to Linux. The program compiles fine, but terminates with a segmentation fault when executed.
The segfault occurs when the program tries to open a file (the file exists ;). Strange to say, the program succeeds in opening another file earlier in the execution without an error. Both files are binary files.
Stepping through the program with gdb, I could track down the last line executed to
DIO.Open (FP (File), To_FCB (Mode), Name, Form);
which is defined in a-direio.adb, line 167.
How can I further investigate the cause of the fault? The values of the parameters to DIO.Open look OK (they are the same as for the previous successful call to DIO.Open, except for the file name). Any hints are appreciated.
Edit
Here is the code that eventually calls DIO.Open:
procedure Open
(The_File : in out File_Type;
The_Mode : in A_DB_Mode := DBS_Database_Types.InOut_DB;
The_Name : in String;
The_Form : in String := "") is
begin
Ada_File_IO.Open
(File => The_File,
Mode => DB_Mode_To_File_Mode(The_Mode),
Name => The_Name,
Form => The_Form);
exception
when Ada_File_IO.Status_Error => raise Status_Error;
when Ada_File_IO.Name_Error => raise Name_Error;
when Ada_File_IO.Use_Error => raise Use_Error;
end Open;
where ADA_File_IO is declared as
package Ada_File_IO is
new Ada.Direct_IO(Element_Type => GNL_Universal_Representation.An_Item);
GNL_Universal_Representation.An_Item resolves to
subtype An_Item is GNL_Basic_Types.A_Byte;
type A_Byte is mod 2**Byte_Size;
and DB_Mode_To_File_Mode(The_Mode) resolves to Ada_File_IO.In_File.
Edit (2)
This is the gdb output with some filenames (as suggested by Brian)
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0xb563db40 (LWP 9887)]
0x081053af in system.file_io.open ()
(gdb) bt
#0 0x081053af in system.file_io.open ()
#1 0x080fd447 in system.direct_io.open ()
#2 0x08066182 in dbs_file.ada_file_io.open (file=0x0, mode=in_file, name=...,
form=...)
at /media/chmiwah/ADA/lib/gcc/i686-pc-linux-gnu/4.7.4/adainclude/a-direio.adb:167
#3 0x080665cc in dbs_file.open (the_file=0x0, the_mode=in_db, the_name=...,
the_form=...)
at /media/chmiwah/GISMO/bbp-benchmark/code/rebsys/src/dbs/ntv/bdy/dbs_file.adb:108
#4 0x080631b0 in dbs_database.open (the_database=0xb5500468, the_mode=in_db,
the_name=..., the_form=..., using_the_definition=0xb5646008)
at /media/chmiwah/GISMO/bbp-benchmark/code/rebsys/src/dbs/gnc/bdy/dbs_database.adb:363
I see you are using a multi-threaded program. When using gdb, note that 'bt' will not be terribly useful, as it only shows one thread (I can't rememeber if this is the main thread or the current thread).
Instead, using the following:
thread apply all bt
or
thread apply all bt full
Also, using strace -f -e trace=file your_program args will be useful to determine if the fault comes before or after the system call to open.
It would be quite useful to know what version of the compiler you are using, and what options were used to build it (esp. if any warnings were disabled).
Are the filename encoding anything more or less than US-ASCII?
Related
I started using fmt for printing recently. I really like the lib, fast, easy to use. But when I completed my conversion, there are ways that my program can run that will render with a bunch of additional newlines. It's not every case, so this will get a bit deep.
What I have is a compiler and a build manager. The build manager (picture Ninja, although this is a custom tool) launches compile processes, buffers the output, and prints it all at once. Both programs have been converted to use fmt. The key function being called is fmt::vprint(stream, format, args). When the build manager prints directly, things are fine. But when I'm reading the child process output, any \n in the data has been prefixed with \r. Windows Terminal will render that fine, but some shells (such as the Visual Studio output window) do not, and will show a bunch of extra newlines.
fmt is open source so I was able to hack on it a bunch and see what is different between what it did and what my program was doing originally. The crux is this:
namespace detail {
FMT_FUNC void print(std::FILE* f, string_view text) {
#ifdef _WIN32
auto fd = _fileno(f);
if (_isatty(fd)) {
detail::utf8_to_utf16 u16(string_view(text.data(), text.size()));
auto written = detail::dword();
if (detail::WriteConsoleW(reinterpret_cast<void*>(_get_osfhandle(fd)),
u16.c_str(), static_cast<uint32_t>(u16.size()),
&written, nullptr)) {
return;
}
// Fallback to fwrite on failure. It can happen if the output has been
// redirected to NUL.
}
#endif
detail::fwrite_fully(text.data(), 1, text.size(), f);
}
} // namespace detail
As a child process, the _isatty() function will come back with false, so we fall back to the fwrite() function, and that triggers the \r escaping. In my original program, I have an fwrite() fallback as well, but it only picks up if GetStdHandle(STD_OUTPUT_HANDLE) returns nullptr. In the child process case, there is still a console we can WriteFile() to.
The other side-effect I see happening is if I use the fmt way of injecting color, eg:
fmt::print(fmt::emphasis::bold | fg(fmt::color::red), "Elapsed time: {0:.2f} seconds", 1.23);
Again Windows Terminal renders it correctly, but in Visual Studio's output window this turns into a soup of garbage. The native way of doing it -- SetConsoleTextAttribute(console, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);-- does not trigger that problem.
I tried hacking up the fmt source to be more like my original console printing code. The key difference was the _isatty() function. I suspect that's too broad of a question for the cases where console printing might fail.
\r is added because the file is opened in text mode. You could try (re)opening in binary mode or ignore \r on the read side.
Thanks in advance for any help. I am currently doing some beginner work on ada programming and I have installed GNAT Programming Studio (GPS) from http://libre.adacore.com/download/configurations#
I have Windows 10 64-bits. I was given the following code at school:
pragma Task_Dispatching_Policy(FIFO_Within_Priorities);
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Real_Time; use Ada.Real_Time;
procedure PeriodicTasks is
Start : Time;
package Duration_IO is new Ada.Text_IO.Fixed_IO(Duration);
package Int_IO is new Ada.Text_IO.Integer_IO(Integer);
task type T(Id: Integer; Period : Integer) is
pragma Priority(Id);
end;
task body T is
Next : Time;
X : Integer;
begin
Next := Start;
loop
Next := Next + Milliseconds(Period);
-- Some dummy function
X := 0;
for Index in 1..5000000 loop
X := X + Index;
end loop;
Duration_IO.Put(To_Duration(Clock - Start), 3, 3);
Put(" : ");
Int_IO.Put(Id, 2);
Put_Line("");
delay until Next;
end loop;
end T;
-- Example Task
Task_P10 : T(10, 250);
Task_P12 : T(12, 500);
Task_P14 : T(14, 500);
Task_P16 : T(16, 250);
Task_P18 : T(18, 500);
Task_P20 : T(20, 250);
begin
Start := Clock;
null;
end PeriodicTasks;
I opened the file in GPS, built it (no errors) and ran it but it doesn't show any printed output. I have heard that sometimes you get issues with multicore CPUs, so everytime the gps.exe is opened, the CPU affinity is set to only one CPU and it is always "Run as Administrator". However, this did not work either, I get no output.
I decided to use Oracle Virtual Box and set up an Ubuntu OS (32 bits) with only one processor. Installed the GNAT tools, compiled with gnatmake, ran with ./periodictasks, and guess what, the program did what it is supposed to do and printed out the info.
After all this long story, does anybody know why this is happening? Could it be a 64 bit vs 32 bit situation?
Thank you very much!
Until recently, GNAT didn't check for integer overflow by default. It did check for constraint errors, e.g. assigning 0 to a Positive.
Many of us thought this was a strange choice by the compiler developers, because it led to many questions whose root cause was failure to handle integer overflow. The recent change leads us to suppose that the developers now agree!
Your problem arises because of the statement
for Index in 1..5000000 loop
X := X + Index;
end loop;
which would end up with X ~ 10^13, which doesn’t fit in a 32-bit integer (it would fit in a 64-bit integer, but that would be a Long_Long_Integer on most if not all GNAT platforms).
It’s likely that your Windows compiler is GNAT GPL 2016, which shows the new behaviour, while the Ubuntu compiler is an older FSF GCC.
You can tell your Windows compiler to use the old behaviour using the compiler switch -gnato0.
You can tell your Ubuntu compiler to use the new behaviour using the compiler switch -gnato.
To get an exception message on unhandled exceptions in tasks (which otherwise die silently), you can add
GNAT.Exception_Traces.Trace_On (GNAT.Exception_Traces.Unhandled_Raise);
at the beginning of your main program.
at the beginning of the execution, there is garbage printed and the only tasks that print information are Task_P20 & Task_P18.
As discussed in §9.2 Task Execution - Task Activation, the tasks are activated together before the first statement of PeriodicTasks executes. Although all tasks are running, no, some or all tasks may try to produce output before Start is initialized. At a minimum, initialize Start as close to its declaration as possible,
Start : Time := Clock;
and leave the body empty,
begin
null;
end PeriodicTasks;
Moreover, a task that fails to activate becomes a completed task, producing no output.
I'm currently finishing my first Haskell Project and, on the final step of the work, my I/O function seems to behave strangely after I connected the different haskell files.
I have a main file (f1.hs) which loads some info of a multimedia library and saves it into variables on a new .hs file (f2.hs). I also have a "data processing and user interface" file (f3.hs), which reads those variables and, depending on what the user orders, it sorts them and displays them on screen. This f3.hs file works with menus, commanded by the valus of the keyboard input (getLine).
In order to make the work sequence "automatic", I made a "main" function on the f1.hs file, which creates the f2.hs file and then with the System.Cmd module, I did a system "runhaskell f3.hs". This routes the user from the f1.hs file to the main function of f3.hs.
The strange thing is that, after I did that, all the getLine seem to appear before the last line of the function prompt.
What it should appear would be:
Question One.....
Answer: (cursor's place)
but what I get is:
Question One.....
(cursor's place)
Answer:
This only happens if I runhaskell f1.hs. If I try to runhaskell f3.hs directly, it works correctly (though I can't do it on the final job, as the f2.hs file needs to be created first). Am I doing something wrong with this sequence?
I'm sorry for the lack of code, but I thought that it wouldn't be any help for the understanding of the problem...
This is typically caused by line buffering, meaning the text does not actually get printed to the console until a newline is printed. The solution is to manually flush the buffer, i.e. something like this:
import System.IO
main = do ...
putStr "Answer: "
hFlush stdout
...
Alternatively, you can disable buffering by using hSetBuffering stdout NoBuffering, though this comes at a slight performance cost, so I recommend doing the flushing manually when you need to print a partial line.
I'm having the following problem. I want to write a program in Fortran90 which I want to be able to call like this:
./program.x < main.in > main.out
Additionally to "main.out" (whose name I can set when calling the program), secondary outputs have to be written and I wanted them to have a similar name to either "main.in" or "main.out" (they are not actually called "main"); however, when I use:
INQUIRE(UNIT=5,NAME=sInputName)
The content of sInputName becomes "Stdin" instead of the name of the file. Is there some way to obtain the name of files that are linked to stdin/stdout when the program is called??
Unfortunately the point of i/o redirection is that you're program doesn't have to know what the input/output files are. On unix based systems you cannot look at the command line arguments as the < main.in > main.out are actually processed by the shell which uses these files to set up standard input and output before your program is invoked.
You have to remember that sometimes the standard input and output will not even be files, as they could be a terminal or a pipe. e.g.
./generate_input | ./program.x | less
So one solution is to redesign your program so that the output file is an explicit argument.
./program.x --out=main.out
That way your program knows the filename. The cost is that your program is now responsible for openning (and maybe creating) the file.
That said, on linux systems you can actually find yout where your standard file handles are pointing from the special /proc filesystem. There will be symbolic links in place for each file descriptor
/proc/<process_id>/fd/0 -> standard_input
/proc/<process_id>/fd/1 -> standard_output
/proc/<process_id>/fd/2 -> standard_error
Sorry, I don't know fortran, but a psudeo code way of checking the output file could be:
out_name = realLink( "/proc/"+getpid()+"/fd/1" )
if( isNormalFile( out_name ) )
...
Keep in mind what I said earlier, there is no garauntee this will actually be a normal file. It could be a terminal device, a pipe, a network socket, whatever... Also, I do not know what other operating systems this works on other than redhat/centos linux, so it may not be that portable. More a diagnostic tool.
Maybe the intrinsic subroutines get_command and/or get_command_argument can be of help. They were introduced in fortran 2003, and either return the full command line which was used to invoke the program, or the specified argument.
I make several calls to a function that reads data from an input file. Everything works fine in debug mode, but when I try to run the executable from release mode, the line with fopen crashes the program after a few calls. My code is:
From header file:
#define presstankdatabase "presst_database.txt"
In function:
FILE *fidread;
fidread = fopen(presstankdatabase,"r");
if (fidread==NULL) {
printf("Failed to open pressurant tank database: %s\n",presstankdatabase);
return 1;
}
In debugging, I've inserted comment lines just before and just after the line starting with fidread =, and after several calls the program crashes and I get the message "A problem caused the program to stop working correctly. Please close the program." The comment just before the fopen call is displayed, but the comment just after does not. My understanding of fopen is that is should return either a pointer or NULL, but it crashes before it even gets to the check. The only thing I can think of is that somehow I'm having memory problems, but I don't know how that would fit in with fopen crashing. Does anyone know what might be going on? Thanks!
EDIT 1: I increased the size of three variables, and the only places they're used (except in printf() calls), are as shown below.
char *constid = (char*)malloc(sizeof(char)*20);
Used like so:
strcpy(constid,"Propellant");
strcpy(constid,"Propellant tank");
strcpy(constid,"Pressurant tank");
If the variables are sized to 20, as shown above, it crashes. But if they're larger (I've tried 120 and 100), the program runs. The variables aren't used in any other places other than fprintf() or printf() calls.
presstankdatabase should be a pointer to a string containing the filename to open. If fopen() crashes then that pointer is probably invalid (or NULL). Without any more code it is not possible to debug it further. Use the VC debugger to see what's happening...
EDIT:
Another common cause of this is a filename string that suddenly stops being NULL-terminated.
You should add a printf() call to print the filename before opening. It will most probably fail to produce the expected output. If not, then you have a more interesting form of memory corruption that will take some more work to weed out.
EDIT 2:
If the printf() call shows the correct string, then you probably have memory corruption somewhere else in your code that has mangled some internal structure of the C library. A common cause is going beyond the end (or the beginning for that matter) of a static array or a region provided by malloc().