The purpose of this material is to provide students with, or remind them of, the answers to Frequently-Asked Questions (FAQ) about course-related information, for example:
Do I need to read the whole FAQ?
Indeed not! Material in the FAQ is not part of the material for the course. However, in the interest of reducing question fatigue for the instructor and instructional coordinator, you should always look in the FAQ first for a possible answer to your question.
The course newsgroup uw.cs.cs343 is
another source of information.
NOTE: Information of particular importance is preceded by "NOTE:".
Please send any corrections or suggestions to cs343@student.cs.
make?makefile is set up correctly?delete this in an object's member routine?string class in C++?integer to a string in C++?itoa not work for integer-to-string conversions?Various software, on-line documents, and services are provided to students to facilitate working on assignments. This section briefly summarizes these resources by answering the following questions:
The GNU C++ compiler g++, and the μC++ translator
u++ are provided in the undergraduate environment for compiling
assignments. See man gcc or the C++
Tutorial for more details on g++. See man u++ or
the μC++
Annotated Reference Manual for more details on u++.
There is no port of μC++ to WINDOWS.
The submit command is provided to electronically submit assignments.
See man submit for more information. For example, to submit files
in directory a1 for assignment 1 enter:
% submit cs343 1 a1
which produces important messages describing its activities. Make sure you read these messages!
NOTE: submit for CS343 completely replaces your
submission every time you use it, and all *txt files greater than
250 lines in length are rejected. submit tells you about both of
these actions in its output messages.
If you accidentally submit an incorrect file or multiple versions of a file, please
remove it using the -delete option of submit.
To check on a previous submission enter:
% submit cs343 1 -list
which produces a listing of files previously submitted in a format similar to
ls -l for the specified assignment.
NOTE: try the -list option before
deciding submit has not worked properly. It is your
responsibility to make sure all of your files have been submitted.
Alternatively, this link
gives a list of the files expected by submit in one column of a table, and
gives a list of the files copied by submit to our handin directory
in the other column, so you can compare what is submitted against what is
expected.
This link gives you a means of checking the number of lates you have left.
make?
This link gives you basic information on
make files, including some sample makefiles.
makefile is set up correctly?
This link
gives you a means of checking that you are using the correct version of
make, that your makefile has been set up correctly,
and that your submitted code compiles into the requested executable names.
In general, there is no way to do this. Once a file has been deleted (usually
with rm) or altered and saved, the previous version is gone.
However, you can attempt to deal with these accidents in two ways: recover an
older version of the file from backup storage or prevent the accident in the
first place.
See MFCF's restore FAQ for detailed information on retrieving a backed up file.
You can attempt to prevent accidental file changes by using the -i
option of rm when deleting files (i.e., rm -i
<files>), or by making backup copies of your files before editing
them (e.g., cp <file> <file>.1), or by archiving old copies of your files.
Delete them! Do not leave junk lying around. If you want or need to keep some of your old files, read about keeping files.
If you want to keep a file or a directory containing a group of files for later reuse, then consider compressing it. A compressed file or directory contains the original file's or directory's contents in an encoded form that occupies less disk space. See MFCF's compress FAQ for detailed information on compressing a file or a directory of files.
The amount of disk memory a user is permitted to occupy is called the disk quota. See MFCF's quota FAQ for detailed information on displaying quota information.
The UNIX commands script and scriptfix are available
to make a record of shell activity. The script program, once
invoked, copies all the activity of a shell session into a file, which is handy
for recording a sequence of commands and their results for later inspection.
Therefore, the script command lends itself to debugging, testing,
and reporting errors. A typical use of
script is given here:
% script foo
which makes a copy of all future shell activity in file foo. The
exit command is used to end the script session.
Since script records control characters (such as backspace) in
their raw form, it is important to use the scriptfix command to
make the file foo clean and legible. The scriptfix
program cleans up extraneous characters from a script file so it is readable.
A typical use of scriptfix is given here:
% scriptfix foo > bar
which cleans the script file foo and redirects the result into the
file bar. The scriptfix command should always be run
on script files that are submitted for assignments.
NOTE: scriptfix does not remove DOS newlines. In
order to remove these, use the dos2unix utility.
The local newsgroup uw.cs.cs343 is for the posting of information
and questions relevant to the material covered in the course and for discussion
of assignments. Generally, appropriate postings include informational messages
from course staff, and error reports or
information requests from students.
Other postings related to course material are also acceptable, but general discussions or personal requests should be carried on in other newsgroups, by email, or in person. A good rule of thumb is to make course material (e.g., assignments, class notes, etc.) the subject of your postings, rather than your own solutions or suggestions.
NOTE: students are expected to read the newsgroup regularly (usually every day) to stay current on any course-related developments. Doing so is solely the student's responsibility.
NOTE: there is an unfortunate tendency of newsgroup postings (and email messages) to become judgemental or to be interpreted uncharitably. This situation can result in so-called `flame wars' and unnecessarily aggressive posturing. Flaming is not tolerated in a course newsgroup! The most reasonable way to avoid this problem is to exercise patience when posting. "Is this posting really necessary?", "Is my phrasing clear and appropriate?", and "Would direct email be better than a public newsgroup?" are always good questions to ask yourself when regarding a potential posting. Finally, always read your posting twice before sending it.
Normally, a good way to get help on some aspect of the UNIX operating system and
shell commands is to read the man page for the particular feature
or command. Manual pages related to a certain topic can be searched for with
the -k option of man (see man man for details).
Also, MFCF has consultants in MC 3011 who can answer general questions and
provide information about using UNIX in the undergraduate environment. You can
also email them questions at consultant@math. See The Math Faculty Computing
Facility for more details.
NOTE: the consultants are NOT there to do your assignment for you!
There is no single book that suits everyone's taste; it dependents on how you learn. For example, some people learn best with books that have lots of examples and explanations; others want only a reference book with just the facts and details. The point is that you must select a book that works for you. It is virtually impossible for someone else to do it.
You may also want to consider the text books recommended in CS 246.
This section briefly outlines the policies for the CS343 course regarding submissions and remarking of submissions.
Assignments are usually considered due at 6pm on the date listed on the assignment itself. Assignments may usually be handed in late up to N days after they are due, where N is course dependent. For N = 2, an assignment due on a Tuesday, has a late date on Thursday. Should the late date be a University holiday, the late date is pushed to the next day the University is open. Assignments may not be due after the last day of lectures, so if an assignment due-date falls on the last day of lectures, there can be no corresponding late date.
A student may submit up to M assignments late without penalty, where M is
course dependent; any further late submissions are not accepted and a grade of
0 is assigned for that assignment. The submit command is
configured to automatically enforce this policy. Requests for extensions may
be granted provided there is good reason for the student not being able to
complete the assignment on time (e.g., a note from a doctor). Extensions are
rare.
NOTE: Instructions given with any assignment always take precedence over these rules, so be sure to check the assignment statement carefully. It is solely the student's responsibility to comply with the requirements of any assignment.
Each marker puts their initials at the top of the marking sheet. If you have a question about your marks for an assignment, see the marker during their office hour. The office hours are posted on the CS343 people page after the first assignment.
A student may request the remarking of an assignment up to 2 weeks after that assignment has been returned. A request for remarking must be made to the original marker and must include all the material returned to the student. This includes simple addition errors. The marker may also request a separate sheet, written by the student, that explains what is to be remarked and why. The marker then reports any change of grade to the course tutor or Instructional Support Coordinator.
The policy regarding midterm remarking is announced after the midterm is returned, and is similar to the assignment remarking.
If you are unhappy with your final grade because your final-exam mark is lower than you expected, you must file a formal grade appeal to have your final exam remarked. You do this by going to the Math Undergrad Office and filling out a grade-appeal form.
Never assume you can use a feature/technique in an assignment unless it has been discussed in class. In general, an assignment is a mechanism to practise some concept/idea/approach presented in class. Therefore, it is the purpose of the solution for an assignment to reflect this concept/idea/approach. Features/techniques discussed in class or explicitly specified in the assignment are usually the ones you are suppose to use. Solving the assignment using some other feature/technique does not provide the desired practise, even if the solution might be easier using the other feature/technique.
However, in many cases an assignment may involve the use of many features/techniques, some of which are crucial and some not. Therefore, it never hurts to ask the assignment coordinator, if a particular feature/technique is allowed. It is always better to ask, and ask early, so you do not have to redo parts of your assignment or are surprised at your assignment mark when it is returned.
NO! Interfaces provide the plugs that allow connecting parts of a program together. When you are given an interface you must respect it or other programs cannot plug into the service it provides. It does not matter that you are writing all the components of the program in an assignment, and hence, control all the interfaces. You must learn to develop programs from specifications, which often include specific interfaces. Hence, you can ask about altering an interface, but 99% of the time the answer will be NO.
Working in a group usually requires sharing access to files. Sharing files must not involve sharing account passwords or making files readable/writable by everyone. The proper way to share files for course-group access is to create a UNIX file-group, in which all userids for group members are listed. Then the UNIX file-group and file-group permissions (read/write) are added to each shared file, allowing only those userids associated with the file-group to access the files.
A UNIX file-group can only be created indirectly through a request to the course Instructional Support Coordinator (ISC). MFCF does not create arbitrary UNIX file-groups for students. As well, funneling the requests through the ISC allows requests to be batched together so MFCF can create the UNIX file-groups for an entire course in a single operation.
After MFCF has created the groups, the ISC emails the UNIX group-name to the requester. A group-name is usually of the form cs343_NN where NN is a number. See man -s i groups for further information on how to associate a UNIX group-name with a file so it can be shared among users (you will need to logout and back in again for the changes to your .cshrc file to take effect). NOTE: a shared file occupies space in only one account; other members of the group can create symbolic links (see man ln) to facilitate easy access to the shared file.
Problems with software for the course can and do occur. Also, problems occur when you are building software for your assignments. This section briefly summarizes some of these problems.
The proper reporting of potential software errors is important in solving problems and keeping the course progressing smoothly. Vague or incomplete error reports may simply frustrate both reporter and fixer. Please follow these general steps when reporting an error (whether electronically or in person):
Be sure that the error is really an error. Simply getting an error message does not mean something is broken. You may also find, in following the steps below, that the explanation of an error becomes apparent to you. In any case, the first step in reporting an error is ensuring you have considered all the relevant information. This often means:
man page(s)This step should help you find the cause of errors and prevent trivial or ambiguous error reports.
If after checking all available resources the error remains, prepare an error report that reflects your efforts in the previous step. Often, this means sending a posting or email message that provides the following information:
This information is important since diagnosing an error often requires being able to reproduce it. Reproducing requires knowing what conditions existed before the error, what command(s) produced the error, and why the result is incorrect. Without this information, the amount of guesswork in error diagnosis grows exponentially (well, it gets large).
NOTE: there is a natural tendency to `simplify' the reporting of difficulties by reporting a quasi-problem related to the real problem. If you do not know what the problem is, do not assume you can simplify it without losing important information! A common question from people who handle these difficulties is "what do you really want?"
NOTE: The script and scriptfix commands are particularly well-suited to
preparing error reports with courseware.
Send the error report to the appropriate destination. Depending on the
problem, this could mean emailing the TA, course tutor, instructor, posting to
the course newsgroup or using the MFCF gripe command. If you
happen to figure out the problem after you submit the error report, follow up
with the information! Others may well be interested in what you have found out.
This is important because, having followed the above steps, the error you
reported must be non-trivial and the information should help to improve the
course.
See 17.3.1.2 Headers [lib.headers] of the "International Standard for Information Systems-- Programming Language C++" for C and C++ related header files. Notice, that the standard assumes include files without ".h" as suffix.
NOTE: For μC++ programs, the file uC++.h must always to be included
before any other header files in each source file.
Routines rand and random are not thread-safe, and
hence, are not safe to use in μC++. However, both often work fine
in simple assignment programs. To be correct, use rand_r to
generate random values, e.g.:
unsigned int seed = getpid(); // initialize to some random starting value rand_r( &seed ); // pass the address of the seed, which is modified
Note, each task must have its own variable seed rather than share
the same variable or rand_r becomes thread unsafe.
There are example programs in the examples directory illustrating stream I/O in C++.
See the C++ Tutorial for examples of creating and manipulating a matrix in C++.
delete this in an object's member routine?
An object can commit suicide, i.e., it can "delete this", but it is a fragile operation: (from http://www.parashift.com/c++-faq-lite/freestore-mgmt.html#faq-16.14)
[16.14] Is it legal (and moral) for a member function to say delete this?
As long as you're careful, it's OK for an object to commit suicide (i.e.,
delete this).Here's how I define "careful":
- You must be absolutely 100% positive sure that this object was allocated via
new(not bynew[], nor by placementnew, nor a local object on the stack, nor a global, nor a member of another object; but by plain ordinarynew).- You must be absolutely 100% positive sure that your member function will be the last member function invoked on this object.
- You must be absolutely 100% positive sure that the rest of your member function (after the
delete thisline) doesn't touch any piece of this object (including calling any other member functions or touching any data members).- You must be absolutely 100% positive sure that no one even touches the
thispointer after thedelete thisline. In other words, you must not examine it, compare it with another pointer, compare it withNULL, print it, cast it, do anything with it.Naturally the usual caveats apply in cases where your this pointer is a pointer to a base class when you don't have a virtual destructor.
So yes it can be done, but it should only be done in special circumstances. Now the reason this works for objects is because the stack maintaining the routine calls is independent from the object allocation in the heap storage. Thus, it is possible to return from the object's member using the data on the stack even though the data for the object no longer exists.
HOWEVER, this last point is not true for a coroutine or task
object because it has its own stack. Hence, delete this executed
by a routine call on the coroutine/task stack fails because it causes both the
object and stack to vanish, so the routine cannot continue execution on the
deleted stack. Hence, the following axiom is true "you can commit suicide but
not bury yourself". For an object with its own execution stack, it is always
necessary to delete this kind of object on a stack different from the one that
is being deleted.
string class in C++?
There are example programs in the examples directory illustrating the use
of the string class in C++.
integer to a
string in C++?
Unfortunately, the string type does not provide either an implicit
or explicit conversion to integer, and therefore you have to write
your own, e.g.:
#include <sstream>
#include <string>
std::string itostring( long int i ) {
std::stringstream ss;
ss << i;
return ss.str();
}
While converting from internal representation to a string is sometimes
necessary, it should never be done to imitate Java style I/O in C++.
For example, never do this:
cout << "i = " + itostring( i ) + " j = " + itostring( 5 ) + "\n";
instead do this:
cout << "i = " << i << " j = " << j << endl;
itoa not work for integer-to-string conversions?
itoa is not part of the ANSI C standard library. It is only
implemented in some compilers. So, try something else, like
stringstream, or sprintf.
Floating-point registers are not saved by default during a context switch to reduce execution cost, particularly because most programs do not perform floating-point calculations. Therefore, each task using floating point has to explicitly indicate that the floating-point registers must be saved (see the μC++ Reference Manual on "User Specified Contexts" for details).
One exception is the SUN/SPARC architecture, which implicitly saves both the integer and floating point registers when a context switch occurs, but it is an anomaly among architectures. If you are running μC++ on a PCs or a non-SUN undergraduate machine, you have to explicitly indicate that the floating registers need to be saved for each task.
The following is a list of some often-encountered warning/error-messages for C/C++ and the problems they typically indicate. Undoubtedly, not all the interesting ones are accounted for yet, so please feel free to request that other error messages be included here.
test.cc: In constructor `B::B(int)': test.cc:11: warning: `B::i' will be initialized after test.cc:10: warning: `A B::a' test.cc:12: warning: when initialized here
C++ always initializes class members in the order they are declared not the order specified in the ctor-initializer of a constructor. For example, in:
#include <iostream>
using namespace std;
struct A {
int i;
A( int i ) : i( i ) {}
};
struct B {
A a;
int i;
B( int j ) : i( j ), a( i ) {}
};
int main() {
B b( 7 );
cout << b.i << " " << b.a.i << endl;
}
the member variable "a" is initialized with an undefined value rather than the value of "j", even though the correct initialization ordering is specified in the constructor's ctor-initializer.
ld: elf error ...
Check your diskquota to ensure you have enough space.
test.cc:3: error: return type specification for constructor invalid
test.cc:4: error: return type specification for destructor invalid
A return type is not allowed on a constructor or destructor, e.g.:
class C {
public:
void C(); // no return type
void ~C(); // no return type
};
Undefined first referenced symbol in file C::C() /var/tmp//ccg7n2Cz.o C::~C() /var/tmp//ccg7n2Cz.o
Each prototype definition needs a corresponding implementation, e.g.:
class C {
public:
C(); // forget to define implementation
~C(); // forget to define implementation
};
int main() {
C c; // create instance without complete definition
}
test.cc:3: error: `cout' undeclared (first use this function)
test.cc:3: error: `endl' undeclared (first use this function)
The named variables and routines have not been declared, i.e., violation of
definition before use in C++. This problem often happens if there is a missing
#include or using, e.g.:
// forget to include <iostream.h>
// forgot to import cout, endl
int main() {
cout << "abc" << endl;
}
test.cc:4: error: uninitialized reference member `C::r'
For example, in:
class C {
const int &r;
public:
C() {}
};
the reference variable r must be initialized, but not at
the point of declaration when declared in a class. Instead, initialization must
occur by special syntax on each constructor, e.g.:
class C {
const int &r;
public:
C( int &rp ) : r( rp ) {} // special initialization syntax
};
In file included from test.cc:2: T2.h:1: error: redefinition of `class T2' T2.h:1: error: previous definition of `class T2'
For example, in:
test.cc T1.h T2.h
#include "T1.h" #include "T2.h" class T2 {
#include "T2.h" class T1 { };
int main() { T2 t2;
T1 t1; public:
T2 t2; };
}
both main and T1 need to declare objects of type
T2, so both include T2.h. main also
needs to declare objects of type T1, so it includes
T1.h. However, because T1.h already includes
T2.h, the definition of T2 is included twice in
test.cc. Either remove one of the includes (not always possible),
or use the preprocessor #ifndef/#define/#endif macros to ensure an
include file is expanded only once even if it is included multiple times, e.g.:
T2.h
#ifndef __T2_H__
#define __T2_H__
class T2 {
};
#endif
Bus Error/Segmentation Fault (core dumped)
is caused by a bad (invalid) memory address.
A bus error occurs when the bad memory address is outside the physical bounds of memory. For example:
int main() {
int *ip = (int *)0xffffffff; // VERY LARGE memory address
*ip += 1; // use the bad address
}
the address 0xffffffff exceeds the memory available on the
computer.
A segmentation error occurs when the bad address is within the physical bounds of memory but the address is not part of the user's program or is read-only memory such as for executable code. For example:
int main() {
int *ip = (int *)0x0; // VERY small memory address
*ip += 1; // use the bad address
}
the address 0x0 is not writable because it contains executable
code.
Program errors that cause bus and segmentation errors are typically out-of-bounds array references and/or references through uninitialized or over-written pointers. One of the most common mistakes is to forget to allocate storage for a pointer variable, e.g.:
int main() {
int *ip; // forget to "new" storage
*ip += 1; // use the bad address
}
uses the uninitialized value in pointer ip as a memory address,
which may or may not cause an error.
There are a number of methods for finding out where the program went wrong. One method is to use print statements to determine how far the program is getting before it crashes, and to print out the contents of interesting variables. A more sophisticated method is using a symbolic debugger such as gdb .
The following is a list of some often-encountered warning/error-messages for μC++ and the problems they typically indicate. These errors are generated by the μC++ translator not by the underlying C++ compiler. Undoubtedly, not all the interesting ones are accounted for yet, so please feel free to request that other error messages be included here.
test.cc:17: warning: label `_U_C_fini' defined but not used test.cc:11: warning: label `_U_L000001' defined but not used test.cc:8: warning: label `fini' defined but not used
For example, in:
#include <uC++.h>
_Task T {
public:
void mem() {}
private:
void main() {
fini:
for ( int i = 0; i < 10; i += 1 ) {
_Accept( mem ) {
break fini;
} else;
}
}
};
and using the -Wall compiler flag, these warning messages appear
due to the way μC++ generates code. Labels are generated in a number of
places but are not always used depending on what happens later in the code. It
is too difficult to detect all these cases and remove the labels that are
unnecessary. All of these kinds of warnings can be suppressed by adding the
extra flag:
-Wall -Wno-unused-label
/software/u++-5.2.0/inc/ostream:37: uC++ Translator warning: unrecognizable text, ... /software/u++-5.2.0/inc/ostream:42: uC++ Translator warning: unrecognizable text, ... ... many more errors
This large number of errors occurs from the following include statements:
#include <iostream> #include <uC++.h>
Always put the uC++.h include file first, like this:
#include <uC++.h> #include <iostream>
Undefined first referenced symbol in file T::T[in-charge](int, uAction) /var/tmp//ccojb9um.o T::T[in-charge](uAction) /var/tmp//ccojb9um.o
Each prototype definition needs a corresponding implementation, e.g.:
#include <uC++.h>
_Task T {
void main() {}
public:
T(); // forget to implement
T(int); // forget to implement
};
void uMain::main() {
T t1, t2(3); // create instances without complete definition
}
This case is like the C++ one but notice
the extra parameter uAction in the error message. This parameter
is inserted by μC++ at the end of each constructor's parameter list and should
be ignored when reading the error messages.
test.cc: In member function `virtual void uMain::main()': test.cc:8: error: cannot declare variable `t' to be of type `T' test.cc:8: error: because the following virtual functions are abstract: /software/u++-5.2.0/inc/uC++.h:1570: error: virtual void uBaseTask::main()
Both a coroutine and a task definition must have a member named
main defined, either directly or by inheritance, e.g.:
#include <uC++.h>
_Task T {
// no main member
public:
T() {}
};
void uMain::main() {
T t;
}
test.cc:4: uC++ Translator error: accept on a nomutex member "mem", possibly
caused by accept statement appearing before mutex-member definition.
For example, in:
#include <uC++.h>
_Task T {
void main() {
_Accept( mem );
}
public:
void mem() {}
};
the accept of member mem appears before the definition of
member mem, and hence, the μC++ translator encounters the
identifier mem before it knows it is a mutex member. C++ requires
definition before use in most circumstances.
test.cc:8: uC++ Translator error: multiple accepts of mutex member "mem".
For example, in:
#include <uC++.h>
_Task T {
public:
void mem() {}
private:
void main() {
_Accept( mem );
or _Accept( mem );
}
};
the accept statement specifies the same member, mem, twice. The
second specification is superfluous.
test.cc:6: uC++ Translator error: accepting an invalid destructor; destructor
name must be the same as the containing class "T2".
For example, in:
#include <uC++.h>
_Task T1 {};
_Task T2 {
private:
void main() {
_Accept( ~T1 );
}
};
the accept statement specifies the destructor from a different class,
T1, within class T2.
test.cc:3: uC++ Translator error: derived type "C" of kind "COROUTINE" is
incompatible with the base type "M" of kind "MONITOR"; inheritance ignored.
test.cc:4: uC++ Translator error: derived type "T1" of kind "TASK" is
incompatible with the base type "C" of kind "COROUTINE"; inheritance ignored.
test.cc:5: uC++ Translator error: multiple inheritance disallowed between base
type "M" of kind "MONITOR" and base type "C" of kind "COROUTINE"; inheritance
ignored.
For example, in:
#include <uC++.h>
_Mutex class M {};
_Coroutine C : public M {};
_Task T1 : public C {};
_Task T2 : public M, public C {};
inheritance is restrictioned among kinds of types in μC++ (see the μC++ Reference Manual on "Inheritance" for details).
test.cc:3: uC++ Translator error: "T" redeclared with different kind.
For example, in:
#include <uC++.h>
_Task T; // prototype
_Coroutine T {}; // definition
the kind of type for the prototype, _Task, does not match the kind
of type for the definition, _Coroutine.
test.cc:4: uC++ Translator error: multiple inheritance disallowed between base
type "M1" of kind "MONITOR" and base type "M2" of kind "MONITOR"; inheritance
ignored.
For example, in:
#include <uC++.h>
_Mutex class M1 {};
_Mutex class M2 {};
_Mutex class M3 : public M1, public M2 {}; // multiple inheritance
only one base type can be a mutex type when inheriting.
test.cc:6: uC++ Translator error: mutex attribute of "T::mem" conflicts with
previously declared nomutex attribute.
For example, in:
#include <uC++.h>
_Task T {
public:
_Nomutex void mem();
};
_Mutex void T::mem() {}
the kind of mutual exclusion, _Nomutex, for the prototype of
mem, does not match the kind of mutual exclusion,
_Mutex, for the definition.
test.cc:4: uC++ Translator error: constructor must be mutex, nomutex attribute
ignored.
test.cc:6: uC++ Translator error: destructor must be mutex for mutex type,
nomutex attribute ignored.
For example, in:
#include <uC++.h>
_Task T {
public:
_Nomutex T() {} // must be mutex
_Nomutex ~T() {} // must be mutex
};
a constructor of a mutex type must be mutex because the thread of the constructing task is active in the object, and a destructor must be mutex if it is a member of a mutex type because deletion requires mutual exclusion.
test.cc:2: uC++ Translator error: cannot create anonymous coroutine or task
because of the need for named constructors and destructors.
For example, in:
#include <uC++.h>
_Task /* no name */ {};
a type without a name cannot have constructors or destructors since both are named after the type, and the μC++ translator needs to generate constructors and destructors if not present for certain kinds of types.
test.cc:2: error: 'uSemphore' is used as a type, but is not defined as a type.
For example, in:
#include <uC++.h> uSemphore s;
the type uSemaphore is not automatically defined by the
uC++.h header file. To access type uSemaphore,
include uSemaphore.h.
uC++ Runtime warning (UNIX pid:4823) : program terminating with 1024(0x400)
bytes of storage allocated but not freed. Possible cause is unfreed storage
allocated by the program or system/library routines called from the program.
This warning can (usually) be ignored. For example, in:
#include <uC++.h>
#include <string>
using std::string;
void uMain::main() {
string s = "abc";
}
this message indicates unfreed storage, but it does not imply the storage is
allocated by the user's code. Many system (e.g., exceptions) and library
(e.g., string type and socket I/O) operations allocate storage
(such as buffers) for the duration of the program, and therefore, there is
little reason to free the storage at program termination. (Why clean up and
then terminate?) There is nothing that can be done about this unfreed storage.
Therefore, the value printed is only a guide in determining if all of a user's
storage is freed.
What use is this message? Any sudden increase of unfreed storage from some base value may be a strong indication of unfreed storage in the user's program. For example, one of the most common mistakes in freeing memory is to incorrectly delete dynamically-allocated arrays, as in:
int *intArray = new int[N]; delete intArray; // must be: delete [] intArray
Always follow the rule that if the new has [] so must
the delete. If the [] are forgotten when deleting an
array, C++ only deletes the first element of the array, thinking there is only
one item to delete not N. The remaining N-1 elements
become unfreed storage.
What if this warning message offends you? Is there anything that can be done
to eliminate it? NO! Just ignore it and you will not lose marks. DO NOT use
exit(0) at the end of your program to remove the message because
global destructors are not executed, i.e., the program is stopped immediately
without proper cleanup. DO NOT compile your program with the
-nodebug flag to remove the message because this eliminates many
useful runtime error checks. Marks will be deducted if you take either of
these steps to eliminate this message.
In general, do not worry about this message if you have freed all of the storage you allocated.
/usr/local/u++-5.0.1/src/library/uSocket.cc:817: the use of `tempnam'
is dangerous, better use `mkstemp'
This warning can be ignored. It occurs only on Linux systems
due to an over zealous and paranoid implementor of mkstemp. The
usage of tempnam in μC++ is correct and it
cannot be replaced by mkstemp. If this message
bothers you, please contact the implementor of mkstemp and ask
them to remove the message as it is incorrect in certain cases.
uC++ Runtime error (UNIX pid:13901) Propagation failed to find a matching
handler. Possible cause is a missing try block with appropriate catch clause
for specified or derived exception type or throwing an exception from within a
destructor while propagating an exception. Type of last active exception: int
Error occurred while executing task uMain (0xffbef000).
For example, in:
#include <uC++.h>
void uMain::main() {
throw 1;
}
no try statement with an appropriate catch clause is
in effect so propagation fails to locate a matching handler.
uC++ Runtime error (UNIX pid:13291) Attempt to rethrow/reraise but no active
exception. Possible cause is a rethrow/reraise not directly or indirectly
performed from a catch clause. Error occurred while executing task uMain
(0xffbef000).
For example, in:
#include <uC++.h>
void uMain::main() {
throw; // rethrow
}
because a rethrow must occur in a context with an active (already raised) exception so that exception can be raised again.
uC++ Runtime error (UNIX pid:4258) (uSerial &)0x670c00 : Entry failure while
executing mutex destructor: mutex object has been destroyed. Error occurred
while executing task uMain (0xffbef000).
For example, in:
#include <uC++.h>
_Monitor M {
public:
void mem() {}
};
void uMain::main() {
M *m = new M;
delete m; // delete storage
m->mem(); // make call to mutex member
}
task uMain deletes the monitor m and then calls the
member routine mem through the deleted pointer. As a result, task
uMain finds the mutex object has been destroyed.
uC++ Runtime error (UNIX pid:23337) (uSerial &)0x84470 : Entry failure while
executing mutex destructor, task uMain (0xffbef008) found blocked on
acceptor/signalled stack. Error occurred while executing task T2 (0x8d550).
For example, in:
#include <uC++.h>
_Task T1 {
uCondition w;
public:
void mem() { w.wait(); }
private:
void main() {
_Accept( mem ); // let T2 in so it can wait
w.signal(); // put T2 on acceptor/signalled stack
_Accept( ~T1 ); // uMain is calling the destructor
}
};
_Task T2 {
T1 &t1;
void main() { t1.mem(); }
public:
T2( T1 &t1 ) : t1( t1 ) {}
};
void uMain::main() {
T1 *t1 = new T1;
T2 *t2 = new T2( *t1 );
delete t1; // delete in same order as creation
delete t2;
}
task t2 is allowed to wait on condition variable w in
t1.mem, and then task t1 signals condition
w, which moves task t2 to the acceptor/signalled
stack, and accepts its destructor. As a result, when task uMain
attempts to delete task t1, it finds task t2 still
blocked on the acceptor/signalled stack.
uC++ Runtime error (UNIX pid:23425) (uSerial &)0x84230 : Entry failure while
executing mutex destructor, task uMain (0xffbef008) found blocked on entry
queue. Error occurred while executing task T2 (0x8d310).
For example, in:
#include <uC++.h>
_Task T1 {
public:
void mem() {}
private:
void main() { _Accept( ~T1 ); }
};
_Task T2 {
T1 &t1;
public:
T2( T1 &t1 ) : t1( t1 ) {}
private:
void main() { t1.mem(); }
};
void uMain::main() {
T1 *t1 = new T1;
T2 *t2 = new T2( *t1 );
delete t1;
delete t2;
}
task t2 happens to block on the call to t1.mem, and
then task t1 accepts its destructor. As a result, when task
uMain attempts to delete task t1, it finds task
t2 still blocked on the entry queue of t1.
uC++ Runtime error (UNIX pid:23856) (uCondition &)0x84410 : Waiting failure as
task uMain (0xffbef008) found blocked task T2 (0x8d470) on condition variable
during deletion. Error occurred while executing task T2 (0x8d470).
For example, in:
#include <uC++.h>
_Task T1 {
uCondition w;
public:
void mem() { w.wait(); }
private:
void main() { _Accept( mem ); }
};
_Task T2 {
T1 &t1;
void main() { t1.mem(); }
public:
T2( T1 &t1 ) : t1( t1 ) {}
};
void uMain::main() {
T1 *t1 = new T1;
T2 *t2 = new T2( *t1 );
delete t1;
delete t2;
}
the call to t1.mem blocks task t2 on condition queue
w and then task t1 implicitly accepts its destructor
when its main terminates. As a result, when task
uMain attempts to delete task t1, it finds task
t2 still blocked on the condition queue.
uC++ Runtime error (UNIX pid:26682) (uBaseCoroutine &)0xffbef7b8 : Unhandled
exception in coroutine uMain raised non-locally from resumed coroutine C
(0x8f1d0), which was terminated due to an unhandled thrown exception of type E.
Error occurred while executing task uMain (0xffbef7b8).
For example, in:
#include <uC++.h>
_Event E {};
_Coroutine C {
void main() { _Throw E(); }
public:
void mem() { resume(); }
};
void uMain::main() {
C c;
c.mem(); // first call fails
}
the call to c.mem resumes coroutine c and then
coroutine c throws an exception it does not handle. As a result,
when the top of c's stack is reached, an exception of type
uBaseCoroutine::UnHandledException is raised at
uMain, since it last resumed c.
uC++ Runtime error (UNIX pid:27462) (uBaseCoroutine &)0xffbef7b8 :
Unhandled exception in coroutine uMain raised non-locally from coroutine C1
(0x8f730), which was terminated due to a series of unhandled exceptions --
originally an unhandled thrown exception of type E inside coroutine C2
(0x8acc0). Error occurred while executing task uMain (0xffbef7b8).
For example, in:
#include <uC++.h>
_Event E {};
_Coroutine C2 {
void main() { _Throw E(); }
public:
void mem() { resume(); }
};
_Coroutine C1 {
void main() {
C2 c2;
c2.mem();
}
public:
void mem() { resume(); }
};
void uMain::main() {
C1 c1;
c1.mem(); // first call fails
}
the call to c1.mem resumes coroutine c1, which
creates coroutine c2 and call to c2.mem to resume it,
and then coroutine c2 throws an exception it does not handle. As
a result, when the top of c2's stack is reached, an exception of
type uBaseCoroutine::UnHandledException is raised at
uMain, since it last resumed c.
uC++ Runtime error (UNIX pid:24169) Attempt by coroutine uMain (0xffbef008) to
resume terminated coroutine C (0x823a0). Possible cause is terminated
coroutine's main routine has already returned. Error occurred while executing
task uMain (0xffbef008).
For example, in:
#include <uC++.h>
_Coroutine C {
void main() {}
public:
void mem() { resume(); }
};
void uMain::main() {
C c;
c.mem(); // first call works
c.mem(); // second call fails
}
the first call to c.mem resumes coroutine c and then
coroutine c terminates. As a result, when uMain
attempts the second call to c.mem, it finds coroutine
c terminated. A similar situation can be constructed using
suspend, but is significantly more complex to generate.
uC++ Runtime error (UNIX pid:24258) Attempt to suspend coroutine C (0x82390),
which has never been resumed. Possible cause is a suspend executed in a member
called by a coroutine user rather than by the coroutine main. Error occurred
while executing task uMain (0xffbef008).
For example, in:
#include <uC++.h>
_Coroutine C {
void main() {}
public:
void mem() {
suspend(); // suspend before any resume
}
};
void uMain::main() {
C c;
c.mem();
}
the call to C::mem executes a suspend before the coroutine's
main member is started, and hence, there is no resumer to
reactivate. In general, member suspend is only called within the
coroutine main or non-public members called directly or indirectly from the
coroutine main, not in public members called by other coroutines.
uC++ Runtime error (UNIX pid:24393) Attempt by task T (0x82ea0) to resume
coroutine C (0x831e0) currently being executed by task T (0x83040). Possible
cause is two tasks attempting simultaneous execution of the same coroutine.
Error occurred while executing task T (0x82ea0).
Two tasks cannot simultaneously execute the same coroutine; only one task can use the coroutine's execution at a time. For example, in:
#include <uC++.h>
_Coroutine C {
void main() {
uBaseTask::yield();
}
public:
void mem() {
resume();
}
};
_Task T {
C &c;
void main() {
c.mem();
}
public:
T( C &c ) : c( c ) {}
};
void uMain::main() {
C c;
T t1( c ), t2( c );
}
because t1's thread first calls routine C::mem and
then resumes coroutine c, where it yields the processor.
t2's threads now calls routine C::mem and attempts to
resume coroutine c but t1 is currently using
c's execution-state (stack).
uC++ Runtime error (UNIX pid:24917) Stack overflow detected: stack pointer
0x7a650 below limit 0x7a820. Possible cause is allocation of large stack
frame(s) and/or deep call stack. Error occurred while executing task uMain
(0xffbef008).
uC++ provides no support for automatic growth of stack space for coroutines and tasks. Several checks are made to mitigate problems resulting from lack of dynamic stack growth. For example, in:
#include <uC++.h>
void uMain::main() {
char x[100 * 1024]; // array larger than stack space
verify();
}
the declaration of the array in uMain uses more than the current
stack space (see the μC++
Reference Manual for details on adjusting the stack size).
uC++ Runtime error (UNIX pid:24968) Stack corruption detected. Possible cause
is corrupted stack frame via overwriting memory. Error occurred while
executing task uMain (0xffbef008).
For example, in:
#include <uC++.h>
void uMain::main() {
{
char x[100 * 1024]; // array larger than stack space
for ( int i = 0; i < 100 * 1024; i += 1 ) {
x[i] = 'a'; // write outside stack space
}
} // delete array
verify();
}
the declaration of the array in uMain uses more than the current
stack space, and by writing into the array, the current stack space is
corrupted (and possibly another stack, as well).
uC++ Runtime error (UNIX pid:25043) Attempt to perform a non-nested entry and
exit from multiple accessed mutex objects. Error occurred while executing task
T (0x835f0).
It is a restriction that a task must acquire and release mutex objects in nested (LIFO) order. For example, in:
#include <uC++.h>
_Task T;
_Cormonitor CM {
T *t;
void main();
public:
void mem( T *t ) { // task owns mutex object
CM::t = t;
resume(); // begin coroutine main
}
};
_Task T {
CM &cm;
void main() {
cm.mem( this ); // call coroutine monitor
}
public:
T( CM &cm ) : cm( cm ) {}
void mem() {
resume(); // restart task in CM::mem
}
};
void CM::main() {
t->mem(); // call back into task
}
void uMain::main() {
CM cm;
T t( cm );
}
t's thread first calls mutex routine CM::mem (and now
owns coroutine monitor cm) and then resumes coroutine
cm, which now calls the mutex routine T::mem
(t already owns itself). The coroutine cm resumes
t from within T::mem, which restarts in
CM::mem (full coroutining) and exits before completing the nested
call to mutex routine T::mem (where cm is suspended).
Therefore, the calls to these mutex routines do not terminate in LIFO order.
uC++ Runtime error (UNIX pid:25216) Attempt by task T (0x83050) to activate
coroutine C (0x833c0) currently executing in a mutex object owned by task T
(0x83208). Possible cause is task attempting to logically change ownership of
a mutex object via a coroutine. Error occurred while executing task T
(0x83050).
For example, in:
#include <uC++.h>
_Task T;
_Coroutine C {
T *t;
void main();
public:
void mem( T *t ) {
C::t = t;
resume();
}
};
_Task T {
C &c;
void main() {
c.mem( this );
yield();
}
public:
T( C &c ) : c( c ) {}
void mem() {
resume();
}
};
void C::main() {
t->mem();
}
void uMain::main() {
C c;
T t1( c ), t2( c );
}
because t1's thread first calls routine C::mem and
then resumes coroutine c, which now calls the mutex routine
T::mem. t1 restarts in C::mem and
returns back to T::main and yields the processor.
t2's threads now calls routine C::mem and attempts to
resume coroutine c, which would restart t2 via
c in T::mem. However, this resumption would result
in a logical change in ownership because t2 has not acquired
ownership of t1.
uC++ Runtime error (UNIX pid:25337) Attempt by task uMain (0xffbef008) to call
the destructor for uSerial 0x83278, but this task has outstanding nested calls
to this mutex object. Possible cause is deleting a mutex object with
outstanding nested calls to one of its members. Error occurred while executing
task uMain (0xffbef008).
For example, in:
#include <uC++.h>
class T;
_Monitor M {
public:
void mem( T *t );
};
class T {
M *m;
public:
void mem1() {
m = new M; // allocate object
m->mem( this ); // call into object
}
void mem2() {
delete m; // delete object with pending call
}
};
void M::mem( T *t ) {
t->mem2(); // call back to caller
}
void uMain::main() {
T t;
t.mem1();
}
it is incorrect storage-management to delete any object if there are outstanding nested calls to the object's members. This case is only detected for mutex objects.
uC++ Runtime error (UNIX pid:25431) Attempt by task T (0x82cd0) to call the
destructor for uSerial 0x83a48, but this destructor was already called by task
uMain (0xffbef008). Possible cause is multiple tasks simultaneously deleting a
mutex object. Error occurred while executing task T (0x82cd0).
For example, in:
#include <uC++.h>
_Monitor M {
uCondition w;
public:
~M() {
w.wait(); // force deleting task to wait
}
};
_Task T {
M *m;
void main() {
delete m; // delete mutex object
}
public:
T( M *m ) : m(m) {}
};
void uMain::main() {
M *m = new M; // create mutex object
T t( m ); // create task
delete m; // also delete mutex object
}
it is incorrect to perform more than one delete on a mutex object, which can happen if multiple tasks attempt to perform simultaneous deletes on the same object. This case is only detected for mutex objects.
uC++ Runtime error (UNIX pid:25719) Attempt to delete task T (0x82900) that is
not halted. Possible cause is task blocked on a condition queue. Error
occurred while executing task uMain (0xffbef008).
The destructor of a task cannot execute if the thread of that task has not finished (halted) because the destructor destroys the environment in which the task's thread is executing. For example, in:
#include <uC++.h>
_Task T {
uCondition w;
void main() {
_Accept( ~T ); // uMain invokes destructor
w.wait(); // T continues but blocks, which restarts uMain
}
};
void uMain::main() {
T t;
} // implicitly invoke T::~T
the call to the destructor restarts the accept statement, and the thread of
t blocks on condition w, which restarts the
destructor. However, the destructor cannot cleanup without invalidating any
subsequent execution of task t.
uC++ Runtime error (UNIX pid:6605) Attempt to wait on a condition variable for
a mutex object not locked by this task. Possible cause is accessing the
condition variable outside of a mutex member for the mutex object owning the
variable. Error occurred while executing task T (0x826c8).
Only the owner of a condition variable can wait and signal on it. For example, in:
#include <uC++.h>
_Task T {
uCondition &w;
void main() {
w.wait();
}
public:
T( uCondition &w ) : w( w ) {}
};
void uMain::main() {
uCondition w;
T t( w );
w.wait();
}
the condition variable w is passed from uMain to
t, and then there is a race to wait on the condition. The error
message shows that uMain waited first, and hence, became the
condition owner, and then t's attempt to wait fails. Changing
wait in T::main to signal generates
a similar message with respect to signalling a condition not owned by mutex
object t. It is possible for one mutex object to create a
condition and pass it to another, as long as the creator does not wait on it
before passing it.
uC++ Runtime error (UNIX pid:6502) Attempt to signal a condition variable for a
mutex object not locked by this task. Possible cause is accessing the
condition variable outside of a mutex member for the mutex object owning the
variable. Error occurred while executing task uMain (0xffbef008).
A signal or wait can only occur in a mutex member, since the signal and wait statement access internal data structures of the mutex object (e.g., condition variable, entry queue and acceptor/signalled stack). Therefore, all operations on these data structures must be performed with mutual exclusion. For example, in:
#include <uC++.h>
_Task T {
uCondition w;
void main() { w.wait(); }
public:
_Nomutex void mem() {
w.signal();
}
};
void uMain::main() {
T t;
yield();
t.mem();
}
Changing signal in T::mem to wait
generates a similar message with respect to waiting on a condition not locked
by mutex object t.
uC++ Runtime error (UNIX pid:2159) Attempt to accept in a mutex object not
locked by this task. Possible cause is accepting in a nomutex member routine.
Error occurred while executing task uMain (0xffbef008).
A condition variable must be non-empty before examining data stored with the front task blocked on the queue. For example, in:
#include <uC++.h>
void uMain::main() {
uCondition w;
int i = c.front();
}
the condition variable w is empty, so there is no data to return.
uC++ Runtime error (UNIX pid:2159) Attempt to accept in a mutex object not
locked by this task. Possible cause is accepting in a nomutex member routine.
Error occurred while executing task uMain (0xffbef008).
For example, in:
#include <uC++.h>
_Monitor M {
public:
void mem1() {}
_Nomutex void mem2() {
_Accept( mem1 ); // not allowed in non-mutex member
}
};
void uMain::main() {
M m;
m.mem2();
}
an accept statement is executed in a non-mutex member.
uC++ Runtime error (UNIX pid:2404) Attempt to delete cluster uUserCluster
(0x82260) with task T (0x92770) still on it. Possible cause is the task has
not been deleted. Error occurred while executing task uBootTask (0x5d6f0).
A cluster cannot be deleted with a task still on it, regardless of what state the task is in (i.e., blocked, ready or running). For example, in:
#include <uC++.h>
_Task T {
void main() {}
};
void uMain::main() {
T *t = new T;
}
the uBootTask happens to delete the user cluster after
uMain::main terminates before the dynamically allocated task
t has terminated. Deleting the task associated with
t before uMain::main terminates solves the
problem.
uC++ Runtime error (UNIX pid:2535) Attempt to free storage 0x1 outside the
current heap range:0x5e468 to 0x91b78. Possible cause is invalid pointer.
Error occurred while executing task uMain (0xffbef008).
For example, in:
#include <uC++.h>
void uMain::main() {
int *ip = (int *)1; // invalid pointer address
delete ip;
}
the value of pointer ip is not within the heap storage area, and
therefore, cannot be deleted.
uC++ Runtime error (UNIX pid:2607) Attempt to free storage 0x91c14 with
corrupted header. Possible cause is duplicate free on same block or
overwriting of header information. Error occurred while executing task uMain
(0xffbef008).
For example, in:
#include <uC++.h>
void uMain::main() {
int *ip = new int[10];
delete &ip[5]; // not the start of the array
}
the pointer passed to delete must always be the same as the
pointer returned from new. In this case, the value passed to
delete is in the middle of the array instead of the start.
uC++ Runtime error (UNIX pid:2670) (uSpinLock &)0x92a50.acquire() : internal
error, attempt to multiply acquire spin lock by same task. Error occurred
while executing task uMain (0xffbef008).
For example, in:
#include <uC++.h>
_Task T {
void main() {}
public:
void mem() {}
};
void uMain::main() {
T *t = new T;
delete t;
t->mem(); // use deleted storage
}
an attempt is made to use the storage for task t after it is
deleted, which is always incorrect. This storage may have been reallocated to
another task and now contains completely different information. The problem is
detected inside of the μC++ kernel, where there are assertion checks for
invalid pre or post conditions. In this case, the invalid storage happened to
trigger a check for a task acquiring a spin lock twice, which is never suppose
to happen. Using storage incorrectly can trigger other "internal errors" from
the μC++ kernel.
uC++ Runtime error (UNIX pid:3110) No ready or pending tasks. Possible cause
is tasks are in a synchronization or mutual exclusion deadlock. Error occurred
while executing task uProcessorTask (0x82740).
For example, in:
#include <uC++.h>
#include <uSemaphore.h>
void uMain::main() {
uSemaphore s(0);
s.P(); // block only thread => synchronization deadlock
}
the only thread blocks so there are no other tasks to execute, resulting in a synchronization deadlock. This message also appears for the more complex form of deadlock resulting from mutual exclusion.
uC++ Runtime error (UNIX pid:3241) Attempt to address location 0x0. Possible
cause is reading outside the address space or writing to a protected area
within the address space with an invalid pointer or subscript. Error occurred
while executing task uMain (0xffbef008).
For example, in:
#include <uC++.h>
void uMain::main() {
int *ip = NULL; // set address to 0
*ip += 1; // use the bad address
}
the value of pointer ip is probably within the executable code,
which is read only, but an attempt to write is occurring. This case is like
the C++ one but μC++ provides a more informative
message before terminating the program.
uC++ Runtime error (UNIX pid:3315) Application interrupted by a termination signal.
Error occurred while executing task uMain (0xffbef008).
If a uC++ program is looping for some reason, it may be necessary to terminate
its execution. Termination is accomplished using a shell kill
command, sending signal SIGTERM to the UNIX process. uC++
receives the termination signal and attempts to shutdown the application, which
is important in multikernel mode with multiple processors. For example, in:
#include <uC++.h>
#include <unistd.h> // getpid prototype
void uMain::main() {
kill( getpid(), SIGTERM ); // send SIGTERM signal to program
}
the μC++ program sent itself a termination (SIGTERM) signal.